ScrollViewer 如何缩放滚动?
ScrollViewer how to scale scrolling?
在创建某种图像处理程序时,我 运行 遇到了缩放问题。我使用放置在 ScrollViewer
中的 canvas 作为表面。
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<Canvas Height="{Binding GridHeight}" Width="{Binding GridWidth}">
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"/>
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>
这看起来像这样,当我的应用程序以 windowed 模式启动时:
但是在将其调整为完全 window 模式后,滚动条消失了,但表面的比例保持不变:
这就像我想要的那样工作。但我不希望滚动条消失。
当我更改 canvas 的 ScaleX
和 ScaleY
时,即使表面填充超过整个 ScrollViewer
.
,滚动条也不会重新出现
有没有办法以编程方式更改 ScrollViewer
对象的 ScrollScale 或解决问题的其他方法?
scrollviewer
有HorizontalScrollBarVisibilityProperty
和VerticalScrollBarVisibilityProperty
您应该能够强制这些 visible
在您 xaml 中始终显示。
参见:https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.horizontalscrollbarvisibility?view=netframework-4.7.2#System_Windows_Controls_ScrollViewer_HorizontalScrollBarVisibility
和:https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.verticalscrollbarvisibility?view=netframework-4.7.2#System_Windows_Controls_ScrollViewer_VerticalScrollBarVisibility
进一步阅读。
问题是您的 ScrollViewer 不知道 ScaleTransform 在 Canvas 上所做的更改。我为解决此问题所做的工作是添加 Grid
控件,它将托管 Canvas
控件,并且我将 Grid
的 Height
和 Width
设置为 CanvasHeight * ScaleY
和 CanvasWidth * ScaleX
这样你就可以将特定的尺寸分配给控件,ScrollViewer
会注意到它。
我已经创建了一个演示应用程序,它可以帮助您理解问题,顺便说一句,我在这里发布的代码可以正常工作:
ValueConverter.cs
public class ValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double originalValue = System.Convert.ToDouble(value);
double multiplier = System.Convert.ToDouble(parameter);
return originalValue * multiplier;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double gridHeight = 500.0;
public double GridHeight
{
get { return gridHeight; }
private set { gridHeight = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GridHeight))); }
}
private double gridWidth = 500.0;
public double GridWidth
{
get { return gridWidth; }
private set { gridWidth = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GridWidth))); }
}
private int scaleX = 1;
public int ScaleX
{
get { return scaleX; }
set
{
if (value > 0)
{
var oldScaleX = scaleX;
scaleX = value;
GridWidth *= (double)scaleX / oldScaleX;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScaleX)));
}
}
private int scaleY = 1;
public int ScaleY
{
get { return scaleY; }
set
{
if (value > 0)
{
var oldScaleY = scaleY;
scaleY = value;
GridHeight *= (double)scaleY / oldScaleY;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScaleY)));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
private void btnScaleXIncrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleX++;
}
private void btnScaleXDecrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleX--;
}
private void btnScaleYIncrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleY++;
}
private void btnScaleYDecrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleY--;
}
}
MainWindow.xaml
<Window x:Class="WpfApplicationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplicationTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<local:ValueConverter x:Key="ValueConverter" />
</ResourceDictionary>
</Window.Resources>
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<GroupBox Header="Scale X" DockPanel.Dock="Left" Width="100">
<StackPanel Orientation="Horizontal">
<Button Width="40" Click="btnScaleXIncrease_Click">+</Button>
<Button Width="40" Click="btnScaleXDecrease_Click">-</Button>
</StackPanel>
</GroupBox>
<GroupBox Header="Scale Y" DockPanel.Dock="Right" Width="100">
<StackPanel Orientation="Horizontal">
<Button Width="40" Click="btnScaleYIncrease_Click">+</Button>
<Button Width="40" Click="btnScaleYDecrease_Click">-</Button>
</StackPanel>
</GroupBox>
<StackPanel></StackPanel>
</DockPanel>
<ScrollViewer HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
<Grid Width="{Binding GridWidth, Mode=OneWay}" Height="{Binding GridHeight, Mode=OneWay}">
<Canvas Height="{Binding GridHeight, Mode=OneTime}" Width="{Binding GridWidth, Mode=OneTime}"
Background="Gray">
<Ellipse Fill="Yellow" Height="500" Width="500" StrokeThickness="2" Stroke="Black"/>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"
CenterX="{Binding GridWidth, Converter={StaticResource ValueConverter}, ConverterParameter=0.5, Mode=OneTime}"
CenterY="{Binding GridHeight, Converter={StaticResource ValueConverter}, ConverterParameter=0.5, Mode=OneTime}" />
</Canvas.RenderTransform>
</Canvas>
</Grid>
</ScrollViewer>
</DockPanel>
</Window>
在创建某种图像处理程序时,我 运行 遇到了缩放问题。我使用放置在 ScrollViewer
中的 canvas 作为表面。
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<Canvas Height="{Binding GridHeight}" Width="{Binding GridWidth}">
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"/>
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>
这看起来像这样,当我的应用程序以 windowed 模式启动时:
ScaleX
和 ScaleY
时,即使表面填充超过整个 ScrollViewer
.
有没有办法以编程方式更改 ScrollViewer
对象的 ScrollScale 或解决问题的其他方法?
scrollviewer
有HorizontalScrollBarVisibilityProperty
和VerticalScrollBarVisibilityProperty
您应该能够强制这些 visible
在您 xaml 中始终显示。
参见:https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.horizontalscrollbarvisibility?view=netframework-4.7.2#System_Windows_Controls_ScrollViewer_HorizontalScrollBarVisibility 和:https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.verticalscrollbarvisibility?view=netframework-4.7.2#System_Windows_Controls_ScrollViewer_VerticalScrollBarVisibility
进一步阅读。
问题是您的 ScrollViewer 不知道 ScaleTransform 在 Canvas 上所做的更改。我为解决此问题所做的工作是添加 Grid
控件,它将托管 Canvas
控件,并且我将 Grid
的 Height
和 Width
设置为 CanvasHeight * ScaleY
和 CanvasWidth * ScaleX
这样你就可以将特定的尺寸分配给控件,ScrollViewer
会注意到它。
我已经创建了一个演示应用程序,它可以帮助您理解问题,顺便说一句,我在这里发布的代码可以正常工作:
ValueConverter.cs
public class ValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double originalValue = System.Convert.ToDouble(value);
double multiplier = System.Convert.ToDouble(parameter);
return originalValue * multiplier;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double gridHeight = 500.0;
public double GridHeight
{
get { return gridHeight; }
private set { gridHeight = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GridHeight))); }
}
private double gridWidth = 500.0;
public double GridWidth
{
get { return gridWidth; }
private set { gridWidth = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GridWidth))); }
}
private int scaleX = 1;
public int ScaleX
{
get { return scaleX; }
set
{
if (value > 0)
{
var oldScaleX = scaleX;
scaleX = value;
GridWidth *= (double)scaleX / oldScaleX;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScaleX)));
}
}
private int scaleY = 1;
public int ScaleY
{
get { return scaleY; }
set
{
if (value > 0)
{
var oldScaleY = scaleY;
scaleY = value;
GridHeight *= (double)scaleY / oldScaleY;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScaleY)));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
private void btnScaleXIncrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleX++;
}
private void btnScaleXDecrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleX--;
}
private void btnScaleYIncrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleY++;
}
private void btnScaleYDecrease_Click(Object sender, RoutedEventArgs e)
{
((ViewModel)DataContext).ScaleY--;
}
}
MainWindow.xaml
<Window x:Class="WpfApplicationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplicationTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<local:ValueConverter x:Key="ValueConverter" />
</ResourceDictionary>
</Window.Resources>
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<GroupBox Header="Scale X" DockPanel.Dock="Left" Width="100">
<StackPanel Orientation="Horizontal">
<Button Width="40" Click="btnScaleXIncrease_Click">+</Button>
<Button Width="40" Click="btnScaleXDecrease_Click">-</Button>
</StackPanel>
</GroupBox>
<GroupBox Header="Scale Y" DockPanel.Dock="Right" Width="100">
<StackPanel Orientation="Horizontal">
<Button Width="40" Click="btnScaleYIncrease_Click">+</Button>
<Button Width="40" Click="btnScaleYDecrease_Click">-</Button>
</StackPanel>
</GroupBox>
<StackPanel></StackPanel>
</DockPanel>
<ScrollViewer HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
<Grid Width="{Binding GridWidth, Mode=OneWay}" Height="{Binding GridHeight, Mode=OneWay}">
<Canvas Height="{Binding GridHeight, Mode=OneTime}" Width="{Binding GridWidth, Mode=OneTime}"
Background="Gray">
<Ellipse Fill="Yellow" Height="500" Width="500" StrokeThickness="2" Stroke="Black"/>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"
CenterX="{Binding GridWidth, Converter={StaticResource ValueConverter}, ConverterParameter=0.5, Mode=OneTime}"
CenterY="{Binding GridHeight, Converter={StaticResource ValueConverter}, ConverterParameter=0.5, Mode=OneTime}" />
</Canvas.RenderTransform>
</Canvas>
</Grid>
</ScrollViewer>
</DockPanel>
</Window>