How to save a canvas area centered in ScrollViewer when scaling or exiting, but not everything can be displayed in the viewport

Everything,

I have a WPF application that has a canvas that I wrapped in a scroll viewer. I have a slider in the status bar that allows the user to zoom in and out (just like Win 7 mspaint).

Here are some of the 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> 

When I zoom in and the scroll bars are visible, the scroll bars, no matter where they are set, jump to the middle.

This is exactly as if the scrollbar value remained unchanged, but the maximum value increased.

What can I do to make them ... say if they were in the lower right corner to stay in the lower right corner after zooming in or out?

By the way, here is my increase and decrease code:

 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; } 

So, no rocket in my code, but ...

Refresh the idea: if I had access to the value and the maximum value of the scroll bars, could I get a percentage between them, and then after scaling (scaling) I could reapply the value of the scroll bar as a percentage of the maximum value ????? But where is the value and maximum value available?

Any help would be greatly appreciated. I cannot think that I am the only one who has this problem, since MSPaint (version for Windows 7) is working correctly, and I assume this is a XAML application.

Below is a link (http://www.leesaunders.net/examples/zoomexample/zoomexample.zip) to a minimal working example project (VS 2010). When you run it, just move the scroll bars and then increase the level, you will immediately see the problem.

+7
source share
1 answer

You just need to compensate for the shift that occurs due to scale, because it scales from (0,0). This is a bit more complicated, but here is a sketch of what the method looks like in your example:

 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); } 

It should be perfectly clear; the center location is measured before and after scaling to calculate the shift of this point, which is then added to the current scroll position.

+3
source

All Articles