Shawn

Shawn Wildermuth

Drag and Drop in Silverlight 2


Url: http://wilderminds.blob.core.windows.net/downloads/FunWithDragons.zip

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.