Drag and Drop in Silverlight 2

Silverlight Logo

I've been trolling the Silverlight.NET forums again and there seems to be a lot of questions about Drag-n-Drop again. There are several solutions including a Telerik framework for it that you could look at but I decided to do a very simple example of dragging an item.

The first time I did this was in a Win32 application using Petzold's book (yeah in C...I am that old). Interestingly the problem is the same as its always been. Essentially you have an object you want to be able to drag with the mouse. To do this you need to register for three events:

  • MouseLeftButtonDown: To start the drag operation.
  • MouseMove: To move the item as the mouse moves.
  • MouseLeftButtonUp: To end the drag operation.

To begin, we need to pieces of data about the drag:

public partial class Page : UserControl
{
  bool isDragging = false;
  Point offset;
  // ...
}

The isDragging is simply a flag so when know when dragging is happening.  The offset is a little trickier.  When you drag an item you need to know where on the object you've started the drag so when you move it, you want to give the appearance that the object is being grabbed by the mouse.  The offset is simply the distance between the upper-left part of the dragged object and where the mouse 'grabbed' it.

In the first event (MouseLeftButtonDown) as need to start the dragging:

void theDragon_MouseLeftButtonDown(object sender, 
                                   MouseButtonEventArgs e)
{
  // Mark that we're doing a drag
  isDragging = true;

  // Ensure that the mouse can't leave the dragon
  theDragon.CaptureMouse();

  // Determine where the mouse 'grabbed' 
  // to use during MouseMove
  offset = e.GetPosition(theDragon);
}

First we simply turn on the flag so we can tell we're dragging something. Next we call CaptureMouse to ensure that the mouse stays within the confines of anoobject (in this case the dragged item). This guarantees that you don't accidently lose the dragged item behind the mouse. Lastly, we get the offset by calling GetPosition on the mouse event argument. This mouse event argument has the data associated with the mouse position. By calling GetPosition, we can get a position of where the mouse was in relation to a XAML object (in this case theDragon object we're dragging).

Now that we've started the drag operation we need to move the object as the mouse moves: 

void theDragon_MouseMove(object sender, MouseEventArgs e)
{
  if (isDragging)
  {
    // Where is the mouse now?
    Point newPosition = e.GetPosition(LayoutRoot);
    info.Text = string.Concat("Position: ", 
                              newPosition.X, 
                              " x ", 
                              newPosition.Y);

    // Move the dragon via the new position less the offset
    theDragon.SetValue(Canvas.LeftProperty, 
                       newPosition.X - offset.X);
    theDragon.SetValue(Canvas.TopProperty, 
                       newPosition.Y - offset.Y);
  }
}

If we're in drag mode, we can first get the new position of the mouse (again using GetPosition, but this time we want it in relation to our layout container). Next we simply move it using the new position and the offset. For this example I make it simple and use a Canvas and just change the Canvas.Left and Canvas.Top to move the item. You could use a TranslateTransform to do it if your container isn't a Canvas.

Lastly, we turn off dragging once the user has let go of the mouse button:

void theDragon_MouseLeftButtonUp(object sender, 
                                 MouseButtonEventArgs e)
{
  if (isDragging)
  {
    // Turn off Drag and Drop
    isDragging = false;

    // Free the Mouse
    theDragon.ReleaseMouseCapture();
  }
}

Turning off the flag is useful but make sure you release the mouse capture otherwise your mouse will get stuck in your dragged item.

Hopefully this simple example can help you implement your own more complex drag-n-drop examples.

Comments:

Gravatar

Nice article. Simple and to the point. I was thinking the same thing, as you point out that there are multiple different implementations of drag and drop on forums/blog articles etc and each one offers something different.

Gravatar

Hi Shawn,

That's a nice clear post on a common problem that appears on the forums. I also posted about this recently, and illustrated a way of doing drag and drop over any layout (not just canvas) as well as a simple hittest.

It's available here if anyone needs those options: http://tinyurl.com/8zt98x
Cheers

Ian

Gravatar

Hey Shawn, nice article.

I took this a little step further by providing extension methods for Dragging.

Take a look at those here : http://dev4life.wordpress.com/2009/02/11/silverlight-draggable-extension/

Thanks,
Kunal.

Gravatar

In case of my mouse pointer goes out from the browser window and release the mouse in that case theDragon_MouseLeftButtonUp does not fires. After that when I move mouse on control without pressing it start moves along with mouse. So how can i handle that problem

Gravatar

Shan,

One method is to handle MouseLeave so that you release the mouse when you leave the surface.

Gravatar

Wonderful! I've been struggling to get drag and drop working in Silverlight for ages. . . Thank you very much!!!

Gravatar

how can i add effects while dragging to show the position that i'll drop my item to

Gravatar

Shawn,

We have open sourced our drag drop framework, I have a series of blogs starting here: http://blogs.imeta.co.uk/jyoung/archive/2009/07/21/726.aspx

and a direct download to the source here:
http://www.imeta.co.uk/downloads/iMeta.Silverlight.Windows.zip

Would like your opinion :)


 



 
Save Cancel