
Introduction
“Right, just another drag & drop implementation for Silverlight 2.0, haven’t we seen enough of them yet? You know, something about reinventing the wheel, and stuff?” I know, I know, but I took it as an interesting exercise in control development for Silverlight and to discover more of the Silverlight features. I haven’t yet figured out how to provide you with a live demo of it on this blog so you’ll have to download the code and try it out for yourself (what a shame, a post about Internet application development and no live demo!).
A lot of examples (including the MSDN one) describe a solution with a Canvas and registering some event handlers to mouse events to change the coordinates of the element on the Canvas. Unfortunately this is not the most common scenario. KevD’s Silverlight drag and drop manager project on Codeplex followed another route and looks really feature complete. He (She?) created two new controls, a drag source and a drag target to support arbitrary drag and drop. These are highly customizable and provide a lot of features.
For my exercise I defined the following requirements:
- I wanted drag and drop behavior through an attached property, not through the use of specialized drag and drop controls, or by registering event handlers on every control I want to drag and drop. In my opinion drag and drop is an behavior you attach to any control. This keeps my control tree clean(er).
- No tight coupling between sources and targets of a drag drop operation. They should decide based on the data if something can be dropped.
- Drag data, not controls (but yet still be able to drag controls when needed).
How do I drag and drop in Silverlight?
I defined two attached properties on my custom type DragDropManager. The DragDropManager type contains all the functionality to initiate and finish drag drop operations. For example all event handlings of the controls required in the operation is coded here. The two attached properties are DragDropSourceAdvisor and DragDropTargetAdvisor respectively of types IDragDropSourceAdvisor and IDragDropTargetAdvisor. Here is an example of the use of an drag drop source advisor in XAML:
<UserControl.Resources> <lcl:ListBoxesAdvisor x:Key="lstBoxesAdvisor" /> <DataTemplate x:Key="template"> <Border CornerRadius="5" BorderThickness="2" BorderBrush="SkyBlue" lcl:DragDropManager.DragDropSourceAdvisor="{StaticResource lstBoxesAdvisor}"> <TextBlock Text="{Binding Path=DisplayText}" Margin="2" /> </Border> </DataTemplate> </UserControl.Resources>
The two interfaces are defined like this:
/// <summary>
/// Interface for a drag drop source advisor.
/// </summary>
public interface IDragDropSourceAdvisor
{
/// <summary>
/// Retrieves the data to drag for a drag drop operation.
/// </summary>
/// <param name="element">The element on which a drag operation is started.</param>
/// <param name="dragPoint">The point that was clicked on the
/// <paramref name="element"/> to start the drag.</param>
/// <returns>The data to drag.</returns>
DragInformation RetrieveDragData( DependencyObject element, Point dragPoint );/// <summary>
/// Called when a drag operation is finished.
/// </summary>
/// <param name="element">The element from which data was dragged.</param>
/// <param name="data">The data that was dragged.</param>
/// <param name="userData">The user data provided.</param>
/// <param name="dropped">True if the data is dropped successfully; otherwhise, false.</param>
/// <remarks>Can be used for example to remove the data from the drag source when
/// it was succesfully dropped on a target.</remarks>
void DragFinished( DependencyObject element, object data, object userData, bool dropped );
}/// <summary>
/// Interface for a drag drop target advisor.
/// </summary>
public interface IDragDropTargetAdvisor
{
/// <summary>
/// Checks if an object can be dropped on a target.
/// </summary>
/// <param name="target">The target element to check if <paramref name="value"/> can
/// be dropped on.</param>
/// <param name="value">The value to check if it can be dropped on
/// <paramref name="target"/>.</param>
/// <param name="userData">Possible user data provided by the source advisor.</param>
///
}Share this