Wednesday, 21 November 2012

How to Drag Shapes on a Canvas in WPF

I recently needed to support dragging shapes on a Canvas in WPF. There are a few detailed articles on this you can read over at CodeProject (see here and here for example). However, I just needed something very simple, so here’s a short code snippet that you can try out using my favourite prototyping tool LINQPad:

var w = new Window();
w.Width = 600;
w.Height = 400;
var c = new Canvas();

Nullable<Point> dragStart = null;

MouseButtonEventHandler mouseDown = (sender, args) => {
    var element = (UIElement)sender;
    dragStart = args.GetPosition(element); 
    element.CaptureMouse();
};
MouseButtonEventHandler mouseUp = (sender, args) => {
    var element = (UIElement)sender;
    dragStart = null; 
    element.ReleaseMouseCapture();
};
MouseEventHandler mouseMove = (sender, args) => {
    if (dragStart != null && args.LeftButton == MouseButtonState.Pressed) {    
        var element = (UIElement)sender;
        var p2 = args.GetPosition(c);
        Canvas.SetLeft(element, p2.X - dragStart.Value.X);
        Canvas.SetTop(element, p2.Y - dragStart.Value.Y);
    }
};
Action<UIElement> enableDrag = (element) => {
    element.MouseDown += mouseDown;
    element.MouseMove += mouseMove;
    element.MouseUp += mouseUp;
};
var shapes = new UIElement [] {
    new Ellipse() { Fill = Brushes.DarkKhaki, Width = 100, Height = 100 },
    new Rectangle() { Fill = Brushes.LawnGreen, Width = 200, Height = 100 },
};


foreach(var shape in shapes) {
    enableDrag(shape);
    c.Children.Add(shape);
}

w.Content = c;
w.ShowDialog();

The key is that for each draggable shape, you handle MouseDown (to begin a mouse “capture”), MouseUp (to end the mouse capture), and MouseMove (to do the move). Obviously if you need dragged objects to come to the top in the Z order, or to be able to auto-scroll as you drag, you’ll need to write a bit more code than this. The next obvious step would be to turn this into an “attached behaviour” that you can add to each object you put onto your canvas.

Post a Comment