Implementing Drag-and-Drop Functionality with Mouse Events and Capture

You can add drag-and-drop functionality to a Silverlight plug-in by implementing simple event-handler functions on three mouse events: MouseLeftButtonDown, MouseLeftButtonUp, and MouseMove.The handlers will incorporate the methods CaptureMouse and ReleaseMouseCapture

Drag-and-Drop Functionality in Silverlight vs. True Drag-and-Drop with Clipboard Support

First, a clarification on terminology. In Microsoft Windows or COM development, the term "drag-and-drop" typically connotes that the mechanism of dragging and dropping will also carry an object payload, and the object payload can potentially be used by a target application that is a different application or process than the application that initiated the drag operation. This connotation is not true for Silverlight 2: Silverlight 2 does not implement a clipboard that is capable of exchanging object data between applications. The level of "drag-and-drop" available in Silverlight 2 is more on the level of the ability to capture the mouse, and then to perform actions within the application only. These actions do not and cannot rely on a clipboard, although you can of course store whatever information you need in your own application's properties, call methods, etc. A primary example of a scenario where this is useful is providing a mode whereby the user can reposition objects in layout by clicking the mouse, then holding the mouse as the mouse pointer is moved, and releasing the mouse when the moving object is in the desired layout position.

Implementing Drag-and-Drop Functionality

A drag-and-drop operation in Silverlight 2 is a sequence of three steps:

  • Mouse down. The object is selected. The object should now capture the mouse. Mouse capture gives that object exclusive access to all mouse events generated by the Silverlight plug-in that contains it.

  • Mouse move. The object moves to a new position, relative to the current position of the mouse.

Mouse up. The object stops capturing mouse events and releases capture.

To reiterate, this implementation does not transmit the clipboard contents or any other payload. Silverlight does not permit access to a clipboard in its programming model. The drag-and-drop behavior described in this topic is limited to a single Silverlight plug-in, because each Silverlight  plug-in instance effectively keeps its own self-contained object tree. It is possible to bridge between instances to some degree, by using the hosting browser DOM as the intermediary. For details, see Walkthrough: Calling JavaScript from Managed Code. However, note that mouse capture cannot be retained across instances, unless you provide your own handling for the concept of mouse capture using native JavaScript against the browser DOM.

The following XAML example declares the basic element that will be drag-and-drop aware and the event attributes.

<Canvas
  Width="640" Height="480"
  Background="OldLace" Name="Canvas"
>
<!-- You can drag this rectangle around the canvas. -->
  <Rectangle 
   MouseLeftButtonDown="HandleMouseDown" 
   MouseMove="HandleMouseMove"
   MouseLeftButtonUp="HandleMouseUp" 
   Canvas.Left="30" Canvas.Top="30" Fill="Red" 
   Width="50" Height="50" />
</Canvas>

Starting the Drag-and-Drop Operation

The HandleMouseDown event handler in the following example initiates the drag-and-drop operation by storing the beginning position of the mouse, setting a flag to indicate that the drag-and-drop operation is in effect, and gaining exclusive access to mouse events by calling the CaptureMouse method. When an object has captured the mouse, it receives mouse input regardless of whether the cursor is within its borders.

bool isMouseCaptured;
Point mousePosition;

void HandleMouseDown (object sender, MouseButtonEventArgs e) 
{
  FrameworkElement item = sender as FrameworkElement;
  mousePosition = e.GetPosition(null);
  isMouseCaptured = true;
  item.CaptureMouse();
  item.Cursor = Cursors.Hand;
}

Moving an Object During the Drag-and-Drop Operation

The HandleMouseMove event-handler function in the following C# example determines whether the drag-and-drop operation is in effect by testing the value of the isMouseCaptured variable. If the drag-and-drop operation is in effect, the incremental difference between the last stored mouse position and the current mouse position is applied to the object's Canvas.Top and Canvas.Left values.

void HandleMouseMove (object sender, MouseEventArgs e) 
{
  FrameworkElement item = sender as FrameworkElement;
  if (isMouseCaptured) 
  {

    // Calculate the current position of the object.
    double deltaV = e.GetPosition(null).Y - mousePosition.Y;
    double deltaH = e.GetPosition(null).X - mousePosition.X;
    double newTop = deltaV + (double)item.GetValue(Canvas.TopProperty);
    double newLeft = deltaH + (double)item.GetValue(Canvas.LeftProperty);

    // Set new position of object.
    item.SetValue(Canvas.TopProperty, newTop);
    item.SetValue(Canvas.LeftProperty, newLeft);

    // Update position global variables.
    mousePosition = e.GetPosition(null);
  }
}

Stopping the Drag-and-Drop Operation

The HandleMouseUp event-handler function in the following C# example stops the drag-and-drop operation by setting a flag to indicate that the drag-and-drop operation is no longer in effect, and calling ReleaseMouseCapture. This method releases the object's exclusive access to the Silverlight mouse events. This means that all objects can now receive mouse events.

void HandleMouseUp (object sender, MouseButtonEventArgs e)  
{
  FrameworkElement item = sender as FrameworkElement;
  isMouseCaptured = false;
  item.ReleaseMouseCapture();
  mousePosition.X = mousePosition.Y = 0;
  item.Cursor = null;
}

See Also

Concepts

Mouse Support

Other Resources

Forum Post