Limit the amount of panning to prevent the image from moving out of the window

Introduction:

I exported SVG as XAML and it turned into a Canvas with lots of paths.

After creating the main Canvas content in a simple, auto-generated window, the image was cropped because it was larger than the rectangle of the main window client.

I solved this problem by panning.

Since I plan to continue scaling later, I added a dummy ScaleTransform to the XAML Canvas and changed its RenderTransformOrigin to 0.5 , 0.5 (so that I can scale the image around its center).

I wanted the image to be centered when the window was loaded, so I placed this Canvas inside the Viewbox, which seems to work fine after setting a few properties.

Problem:

Since I changed the RenderTransformOrigin to Canvas, I cannot calculate the math that will allow me to limit the amount of panning.

Despite the fact that Viewbox is the content of the main window, I can’t get the size of the client area of ​​the main window (the size of the "Window Mode" window corresponds to its content). This makes my task even more difficult.

MY EFFORTS TO SOLVE THIS:

There is no other way to get the client window rectangle of the main window except using the P/Invoke and GetClientRect WinAPI GetClientRect .

There was another hack with a SystemParametersInfo request for non-client metrics such as borders and header, but this is an estimate that may fail due to applied topics and the like.

I did not try to use P/Invoke because I just refuse to do it at the moment. There must be a better solution than that! This path should be my last choice, and the one that I will make out of sheer despair.

I tried to find an alternative approach myself, but could not.

I tried using TransformToAncestor(...).Transformtobounds(..) for my calculations, but that also failed.

Question:

How to limit panning, so the image does not disappear from the main window when the user drags too much?

I will make alternative decisions. The code that was presented was an attempt by an inexperienced, novice teacher, so I accept constructive criticism and advice.

RELATED INFORMATION:

To keep this post as short as possible, I give only the relevant XAML snippets and "code behind" below.

The complete code is pasted on Pastebin and can be found at the very end of this post.

Relevant xaml fragments:

 <Window x:Class="TestZaMapu.MainWindow" Name="GlavniProzor" WindowStartupLocation="CenterScreen" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" MouseLeftButtonDown="GlavniProzor_MouseLeftButtonDown" MouseLeftButtonUp="GlavniProzor_MouseLeftButtonUp" MouseMove="GlavniProzor_MouseMove" LostMouseCapture="GlavniProzor_LostMouseCapture"> <Viewbox Name="surface" Stretch="UniformToFill" HorizontalAlignment="Center" VerticalAlignment="Center"> <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Background="Blue" x:Name="svg4306" Width="494.44705" Height="510.55356" <!-- needed in the future, for zooming around center--> RenderTransformOrigin="0.5, 0.5"> <!--Unknown tag: metadata--> <Canvas.RenderTransform> <TransformGroup> <!-- I intend to experiment with scaling in the future, so I added the below part --> <ScaleTransform ScaleX="1" ScaleY="1"/> <!-- I have used dependency properties for translation --> <TranslateTransform X="{Binding TranslationFactorX, ElementName=GlavniProzor, Mode=TwoWay}" Y="{Binding TranslationFactorY, ElementName=GlavniProzor, Mode=TwoWay}"/> </TransformGroup> </Canvas.RenderTransform> <!-- Bunch of Path objects, omitted for brevity--> </Canvas> </Viewbox> </Window> 

Relevant code behind the fragments:

 namespace TestZaMapu { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); TranslationFactorX = 0; TranslationFactorY = 0; isPanning = false; } // panning variables private Point ptOldPosition; private bool isPanning ; // dependency properties for translation along X and Y axes public static readonly DependencyProperty TranslateX = DependencyProperty.Register("TranslationFactorX", typeof(double), typeof(MainWindow)); public static readonly DependencyProperty TranslateY = DependencyProperty.Register("TranslationFactorY", typeof(double), typeof(MainWindow)); public double TranslationFactorX { get { return (double)GetValue(TranslateX); } set { SetValue(TranslateX, value); } } public double TranslationFactorY { get { return (double)GetValue(TranslateY); } set { SetValue(TranslateY, value); } } // mouse event handlers for panning private void GlavniProzor_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if (isPanning ) return; isPanning = this.CaptureMouse(); ptOldPosition = e.GetPosition(this); } private void GlavniProzor_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); if (this.IsMouseCaptured) { this.ReleaseMouseCapture(); isPanning = false; } } private void GlavniProzor_MouseMove(object sender, MouseEventArgs e) { base.OnMouseMove(e); if (isPanning ) { Point ptNewPosition = e.GetPosition(this); if (ptNewPosition != ptOldPosition) { Vector direction = ptOldPosition - ptNewPosition; direction.X = TranslationFactorX - direction.X; direction.Y = TranslationFactorY - direction.Y; TranslationFactorX = direction.X; TranslationFactorY = direction.Y; ptOldPosition = ptNewPosition; } } } private void GlavniProzor_LostMouseCapture(object sender, MouseEventArgs e) { isPanning = false; this.OnLostMouseCapture(e); } } } 

Here is the full XAML, and here the full "code behind."

+8
c # wpf xaml panning
source share
2 answers

I really have not read the complete question (I think no one will), but here is the code that I use in graphics to limit panning. This is math. now add it to you. Hint: Next time enter only the appropriate code so that we can provide a better answer.

I call this method when panning is complete (mouse event in my case)

If that helps, it's libary ( https://github.com/beto-rodriguez/Live-Charts ), maybe you can also help you see the source code. Relax, I think you make it a lot harder than that.

  private void PreventGraphToBeVisible() { var tt = Canvas.RenderTransform as TranslateTransform; if (tt == null) return; var eX = tt.X; var eY = tt.Y; var xOverflow = -tt.X + ActualWidth - Canvas.Width; var yOverflow = -tt.Y + ActualHeight - Canvas.Height; if (eX > 0) { tt.X = 0; } if (eY > 0) { tt.Y = 0; } if (xOverflow > 0) { tt.X = tt.X + xOverflow; } if (yOverflow > 0) { tt.Y = tt.Y + yOverflow; } } 
+1
source share

It sounds criminally simple, but if your goal is to stop your vector from clipping outside its assigned space, why don't you just change the Stretch="UniformToFill" your viewport to Stretch="Uniform" ?

+1
source share

All Articles