C# WPF Canvas – Move shapes around

C

Recently, I needed to support dragging shapes and some other elements on a Canvas in WPF. However, looking online I found several implementations that were more complex than needed and/or not well functioning and I just wanted something very simple and solid. For that reason, below you will find a simple, yet useful implementation which can be easily adapted according to you needs.

Step 1: Create a WPF C# Project and add a Canvas in the main window

<Window x:Class="Canvas_Test.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas  Margin="0" >

    </Canvas>
</Window>

Step 2: Create your shapes inside the canvas

<Window x:Class="Canvas_Test.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas  Margin="0" >
        <Rectangle Width="50" Height="50"  Fill="Red" />
        <Rectangle Width="50" Height="50"  Fill="Green"  />
        <Rectangle Width="50" Height="50"  Fill="Blue" />
    </Canvas>
</Window>

Step 3: Write the proper handlers in the cs

 public partial class MainWindow : Window
    {
        protected bool isDragging;
        private Point clickPosition;
        private TranslateTransform originTT; 

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var draggableControl = sender as Shape;
            originTT = draggableControl.RenderTransform as TranslateTransform ?? new TranslateTransform();    
            isDragging = true;
            clickPosition = e.GetPosition(this);
            draggableControl.CaptureMouse();
        }

        private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            isDragging = false;
            var draggable = sender as Shape;
            draggable.ReleaseMouseCapture();        
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            var draggableControl = sender as Shape;
            if (isDragging && draggableControl != null)
            {
                Point currentPosition = e.GetPosition(this);
                var transform = draggableControl.RenderTransform as TranslateTransform ?? new TranslateTransform();             
                transform.X = originTT.X+ (currentPosition.X - clickPosition.X);
                transform.Y =originTT.Y+ (currentPosition.Y - clickPosition.Y);
                draggableControl.RenderTransform = new TranslateTransform(transform.X, transform.Y);
            }
        }
    }

Step 4: Assign the proper handlers to the shapes

<Window x:Class="Canvas_Test.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas  Margin="0" >
        <Rectangle Width="50" Height="50"  Fill="Red" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseMove="Canvas_MouseMove" />
        <Rectangle Width="50" Height="50"  Fill="Green" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseMove="Canvas_MouseMove" />
        <Rectangle Width="50" Height="50"  Fill="Blue" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseMove="Canvas_MouseMove"/>
    </Canvas>
</Window>

Below is the final output – you will be able to drag-move the boxes around the window

You can also clone the project from github: https://github.com/devcoons/wpf-csharp-canvas-move-items

Disclaimer: The present content may not be used for training artificial intelligence or machine learning algorithms. All other uses, including search, entertainment, and commercial use, are permitted.

  • This project helped me a ton, so I figure I’ll pay it back by leaving this for future viewers.

    If you want to clamp the elements inside the canvas, add this to the canvas element: `x:Name=”Canvas” `
    Then change the code-behind to:
    “`
    protected bool isDragging;
    private Point clickPosition;
    private TranslateTransform originTT;
    private Rect canvasBounds;

    private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
    if (sender is Grid draggableControl)
    {
    originTT = draggableControl.RenderTransform as TranslateTransform ?? new TranslateTransform();
    isDragging = true;
    clickPosition = e.GetPosition(this);
    draggableControl.CaptureMouse();
    canvasBounds = Canvas.RenderTransform.TransformBounds(
    new Rect(0, 0, Canvas.ActualWidth, Canvas.ActualHeight));
    }
    }
    private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
    isDragging = false;
    if(sender is Grid draggableControl) draggableControl.ReleaseMouseCapture();
    }
    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
    if (isDragging && sender is Grid draggableControl)
    {
    Point currentPosition = e.GetPosition(this);
    var transform = draggableControl.RenderTransform as TranslateTransform ?? new TranslateTransform();
    transform.X = Math.Clamp(originTT.X + (currentPosition.X – clickPosition.X), canvasBounds.Left, canvasBounds.Right – draggableControl.ActualWidth);
    transform.Y = Math.Clamp(originTT.Y + (currentPosition.Y – clickPosition.Y), canvasBounds.Top, canvasBounds.Bottom – draggableControl.ActualHeight);
    draggableControl.RenderTransform = new TranslateTransform(transform.X, transform.Y);
    }
    }
    “`

Categories

Tags