放大或缩小时如何保持画布区域在 ScrollViewer 中居中,并且并非所有内容都可以显示在查看窗口中

2024-03-18

每个人,

我有一个 WPF 应用程序,它有一个画布,我将其包裹在滚动查看器中。我在状态栏中有一个滑块,允许用户放大和缩小(就像 Win 7 的 mspaint 一样)。

以下是一些 XAML:

<ScrollViewer Name="Map"
              VerticalScrollBarVisibility="Auto"
              HorizontalScrollBarVisibility="Auto">
    <Canvas x:Name="WallsCanvas" Height="800" Width="1000" ClipToBounds="True">
        <Canvas.LayoutTransform>
            <ScaleTransform x:Name="WallsCanvasScale"
                            ScaleX="1" ScaleY="1" />
        </Canvas.LayoutTransform>
    </Canvas>
</ScrollViewer>

当我放大并且滚动条可见时,滚动条无论设置在哪里,都会跳到中间。

这就像滚动条的值保持不变但最大值增加一样。

我该怎么做才能让他们......比如说,如果他们在右下角,在放大或缩小后留在右下角?

顺便说一句,这是我的放大和缩小代码:

private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    var scales = new []{.125, .25, .5, 1, 2, 4, 8};
    var scale = scales[(int)((Slider) sender).Value];

    ScaleChanged(scale, WallsCanvasScale);
}

private static void ScaleChanged(double scale, ScaleTransform st)
{
    st.ScaleX = scale;
    st.ScaleY = scale;
}

所以,我的代码中没有火箭科学,但是......

更新想法:如果我可以访问滚动条的值和最大值,我可以获取两者之间的百分比,然后在缩放(缩放)之后我可以重新应用滚动条的值作为最大值的百分比价值?????但可用值和最大值在哪里?

任何帮助,将不胜感激。我不认为我是唯一一个遇到此问题的人,因为 MSPaint(Windows 7 版本)可以正常工作,并且我假设它是一个 XAML 应用程序。

这里有一个link http://www.leesaunders.net/examples/zoomexample/zoomexample.zip(http://www.leesaunders.net/examples/zoomexample/zoomexample.zip) 到最小工作示例项目 (VS 2010)。当你运行它时,只需移动滚动条然后放大一个级别,你就会立即看到问题。


您只需要抵消因比例而产生的偏移,因为它是从 (0,0) 开始缩放的。这有点复杂,但以下是示例中的方法的草图:

private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    var slider = (Slider)sender;
    if (!slider.IsLoaded)
    {
        slider.Loaded += (s, le) => SliderValueChanged(sender, e);
        return;
    }

    var scales = new[] { .125, .25, .5, 1, 2, 4, 8 };
    var scale = scales[(int)((Slider)sender).Value];

    // The "+20" are there to account for the scrollbars... i think. Not perfectly accurate.
    var relativeMiddle = new Point((Map.ActualWidth + 20) / 2, (Map.ActualHeight + 20) / 2);
    var oldLocation = CanvasScale.Transform(TemplateCanvas.PointFromScreen(relativeMiddle));

    ScaleChanged(scale, CanvasScale);

    var newLocation = CanvasScale.Transform(TemplateCanvas.PointFromScreen(relativeMiddle));

    var shift = newLocation - oldLocation;

    Map.ScrollToVerticalOffset(Map.VerticalOffset + shift.Y);
    Map.ScrollToHorizontalOffset(Map.HorizontalOffset + shift.X);

    lblScale.Content = scale.ToString("P1").Replace(".0", string.Empty);
}

应该是不言自明的;在缩放之前和之后测量中心的位置以计算该点的移位,然后将其添加到当前滚动位置。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

放大或缩小时如何保持画布区域在 ScrollViewer 中居中,并且并非所有内容都可以显示在查看窗口中 的相关文章

随机推荐