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 的 ScaleXScaleY 时,即使表面填充超过整个 ScrollViewer.

,滚动条也不会重新出现

有没有办法以编程方式更改 ScrollViewer 对象的 ScrollScale 或解决问题的其他方法?

scrollviewerHorizontalScrollBarVisibilityPropertyVerticalScrollBarVisibilityProperty 您应该能够强制这些 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 控件,并且我将 GridHeightWidth 设置为 CanvasHeight * ScaleYCanvasWidth * 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>