I am new to WPF and I am trying to implement Canvas panning on my own.
I have managed to figure out the logic and mechanics that must be applied, but when implementing them I get a strange behavior.
My panning code "works" well, meaning that image is moving in the correct direction, but it "jiggles" ( or "dances" if you like ) while moving.
Below is a small demo app that illustrates the problem.
XAML:
<Window x:Class="CanvasPanning.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Background="Beige">
<Canvas Name="canvas"
Width="200"
Height="200"
Background="Aqua"
MouseLeftButtonDown="canvas_MouseLeftButtonDown"
MouseLeftButtonUp="canvas_MouseLeftButtonUp"
LostMouseCapture="canvas_LostMouseCapture"
MouseMove="canvas_MouseMove">
<Ellipse Stroke="Black" Fill="Beige" Canvas.Left="50" Canvas.Top="50" Width="100" Height="50" />
<Rectangle Stroke="Black" Fill="Red" Canvas.Left="50" Canvas.Top="120" Width="100" Height="50" />
</Canvas>
</Grid>
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CanvasPanning
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Matrix m;
private bool isPanning;
private Point ptOldPanningPosition;
public MainWindow()
{
InitializeComponent();
isPanning = false;
m = canvas.RenderTransform.Value;
}
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (isPanning) return;
isPanning = canvas.CaptureMouse();
if(isPanning)
{
ptOldPanningPosition = e.GetPosition(canvas);
}
}
private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (isPanning)
{
isPanning = false;
canvas.ReleaseMouseCapture();
}
}
private void canvas_LostMouseCapture(object sender, MouseEventArgs e)
{
isPanning = false;
base.OnLostMouseCapture(e);
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
base.OnMouseMove(e);
if(isPanning)
{
Point ptNewPanningPosition = e.GetPosition(canvas);
Vector offset = ptNewPanningPosition - ptOldPanningPosition;
m.OffsetX += offset.X;
m.OffsetY += offset.Y;
ptOldPanningPosition = ptNewPanningPosition;
canvas.RenderTransform = new MatrixTransform(m);
}
}
}
}
You are taking the position relative to the canvas and you are moving the canvas, take the position relate to the window or the containing element the drag is happening
In mouse left down
if(isPanning)
{
ptOldPanningPosition = e.GetPosition(this);
}
And in mousemove
if(isPanning)
{
Point ptNewPanningPosition = e.GetPosition(this);
}