I am a big fan of attached properties and I think it is one of the coolest innovations in WPF. Once you understand the basics of using and creating attached properties, lot of the common activities that typically require some code-behind can be pushed to a class that implements an attached property or a set of attached properties. A good example is the PanelLayoutAnimator from Dan Crevier’s blog.
In this post I’ll try to explain how I have used attached properties to encapsulate the Drag and Drop (DnD) behavior. To have DnD functionality you typically have to subscribe to a set of Drag and Drop events, like DragEnter, DragLeave, DragOver, Drop. These events get fired when you invoke the DragDrop.DoDragDrop() API. Marcelo has done a great job explaining how you can use the DnD behavior in your own WPF apps and I would recommend reading his blog posts. It was certainly a starting point for me! But as I read his posts, I realized that most of the DnD plumbing can be encapsulated into a class and one can provide a much simpler model to attach DnD behavior to controls.
The source of the idea
This idea came to me because in my past life I was an Eclipse developer working on some cool stuff like <AcronymnAlert> GEF, EMF and RCP </AcronymnAlert>. GEF, which stands for Graph Editing Framework, had a neat way of creating Graph Editors and also had a great programming model for implementing the Drag and Drop behavior. Clients using GEF never had to worry about DnD events and instead implemented an interface which had more high level methods in it. A top-level manager class would take care of all the DnD plumbing and would internally call the methods on the interface. Using this concept I have a similar implementation using the power of attached properties.
How is it done?
The heart of this implementation sits in the class DragDropManager, which is the top level manager component that I described earlier. It takes care of all the DnD plumbing and exposes two attached properties: DragSourceAdvisor and DropTargetAdvisor.
public static readonly DependencyProperty DragSourceAdvisorProperty = DependencyProperty.RegisterAttached("DragSourceAdvisor", typeof(IDragSourceAdvisor), typeof(DragDropManager), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDragSourceAdvisorChanged))); public static readonly DependencyProperty DropTargetAdvisorProperty = DependencyProperty.RegisterAttached("DropTargetAdvisor", typeof(IDropTargetAdvisor), typeof(DragDropManager), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropTargetAdvisorChanged)));
All the event registrations happen in the PropertyChangedCallbacks. As you can see, both of these properties point to interfaces: IDragSourceAdvisor and IDropTargetAdvisor. Below I have reproduced these interfaces in their entirety.
public interface IDragSourceAdvisor { UIElement SourceUI { get; set; } DragDropEffects SupportedEffects { get; } DataObject GetDataObject(UIElement draggedElt); UIElement GetVisualFeedback(UIElement draggedElt); void FinishDrag(UIElement draggedElt, DragDropEffects finalEffects); bool IsDraggable(UIElement dragElt); }
public interface IDropTargetAdvisor { UIElement TargetUI { get; set; } bool IsValidDataObject(IDataObject obj); void OnDropCompleted(IDataObject obj, Point dropPoint); }
IDragSourceAdvisor contains methods that queries the source control about the data that needs to be transferred [GetDataObject()], what are the allowed effects [SupportedEffects], the visual feedback [GetVisualFeedback()] and whether the object is draggable [IsDraggable()]. It also contains the method FinishDrag(), which is useful for any cleanup operations on the source-side once the DragDrop operation is completed.
Similarly IDropTargetAdvisor queries the target control whether it accepts this data object [IsValidDataObject()] and the final drop operation [OnDropCompleted()]. For all the pattern enthusiasts out there, this is basically the strategy pattern for the source and target advisors.
How do I use it?
Here comes the best part of using these attached properties. Imagine you have a Canvas on which you would like to move things around, something like a WinForms designer. Note that the Canvas acts as both the drag source and the drop target. In order to have the DnD behavior we will have to setup the attached properties, like so:
<Window.Resources> <local:CanvasDragDropAdvisor x:Key="advisor"/> </Window.Resources> <Canvas Background="White" dnd:DragDropManager.DragSourceAdvisor="{StaticResource advisor}" dnd:DragDropManager.DropTargetAdvisor="{StaticResource advisor}" > ..... ..... </Canvas> </Window>
The class CanvasDragDropAdvisor implements both the IDragSourceAdvisor and the IDropTargetAdvisor. All of the event handling is now taken care by DragDropManager and the Canvas control automatically starts participating in the DnD operations since we have setup the source and target advisors.
So I hope you will agree that this simplifies adding DragDrop behavior to your controls. There are certainly many improvements that I intend to add to this implementation…starting with the naming of the methods (using the Framework Design Guidelines). There is also a possibility to remove some of the methods and make the interfaces even simpler!
Since this post is already getting too long, I will add a sequel and post the source and the Canvas example in that.
To Be Continued…

Does this work with databinding? How can my user controls implement the IDragSourceAdvisor? I have been working with this for a day and I can’t get each element in my list box to be "draggable"
Have an example where you populate a list/stack panel with buttons that are draggable?
Hi Thomas,
Yes, multiple item DnD is not directly supported. But it could be accomplished my maintaining more state info in your advisor classes. When you start the drag and end it with the drop, you could check the selection and decide how many elements you want to move. Your feedback visual could also be dependent on that state. I know I am sounding a little abstract, but let me know if this approach works.
Hi,
nice work!
i’ve just one question, i would like to know how could i implement Drag and Drop of multiple objects on a canvas (just after having selected them with a lasso tool, for exemple). Actually we could drag only one UIElement by one.
I try to implement a mechanism like we find in windows, when selecting icons on the desktop, and moving selected icons anywhere on the desktop!
Any help will be welcome!
Thanks, Thomas
I posted a sequel to this post (part 2): Link
Sounds interesting!
Is there a link to download your sample?
[...] Podila has a great series of four blog posts about a similar scenario, which I highly recommend reading. The main difference between our two [...]
[...] ( Part 1, Part 2, Part 3, Part 4, Part 5, Part 6 [...]
[...] Podila has a great series of four blog posts about a similar scenario, which I highly recommend reading. The main difference between our two [...]
Hi Pavan,
Drag and Drop Manager Functionality is so cool and etendable. I am trying to extend it for user control which has some named elements such as For eg. . I am facing an serialization issue when xamlreader.load is called in DropTragetBase class in ExtractElement. The exact exception is as follows. it is easily reproduble too. I think XamlWriter class doesn’t know about x:Name property of an element. if i remove this propery it works fine. i have also tried specifying x:FieldModifier as private to make it private of this usercontrol. ByDefault it sets as internal variable. But stilll it keeps throwing this exception. I hope you have better solution.
System.Windows.Markup.XamlParseException occurred
Message=”‘_button1′ value cannot be assigned to property ‘Name’ of object ‘System.Windows.Controls.Button’. Cannot register duplicate Name ‘_button1′ in this scope. Error at object ‘_button1′, Line 1 Position 209.”
Source=”PresentationFramework”
LineNumber=1
LinePosition=209
NameContext=”_button1″
StackTrace:
at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType)
at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException)
at System.Windows.Markup.BamlRecordReader.ThrowExceptionWithLine(String message, Exception innerException)
at System.Windows.Markup.BamlRecordReader.ReadPropertyRecordBase(String attribValue, Int16 attributeId, Int16 converterTypeId)
at System.Windows.Markup.BamlRecordReader.ReadPropertyRecord(BamlPropertyRecord bamlPropertyRecord)
at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.BamlRecordReader.Read(BamlRecord bamlRecord, Int32 lineNumber, Int32 linePosition)
at System.Windows.Markup.XamlTreeBuilder.BamlRecordWriterSyncUpdate(BamlRecord bamlRecord, Int32 lineNumber, Int32 linePosition)
at System.Windows.Markup.XamlTreeBuilderBamlRecordWriter.WriteBamlRecord(BamlRecord bamlRecord, Int32 lineNumber, Int32 linePosition)
at System.Windows.Markup.BamlRecordWriter.WriteAndReleaseRecord(BamlRecord bamlRecord, XamlNode xamlNode)
at System.Windows.Markup.BamlRecordWriter.BaseWriteProperty(XamlPropertyNode xamlProperty)
at System.Windows.Markup.XamlTreeBuilderBamlRecordWriter.WriteProperty(XamlPropertyNode xamlPropertyNode)
at System.Windows.Markup.XamlParser.WriteProperty(XamlPropertyNode xamlPropertyNode)
at System.Windows.Markup.XamlParser.ProcessXamlNode(XamlNode xamlNode, Boolean& cleanup, Boolean& done)
at System.Windows.Markup.XamlParser.ReadXaml(Boolean singleRecordMode)
at System.Windows.Markup.TreeBuilderXamlTranslator._Parse()
at System.Windows.Markup.XamlParser.Parse()
at System.Windows.Markup.XamlTreeBuilder.ParseFragment()
at System.Windows.Markup.TreeBuilder.Parse()
at System.Windows.Markup.XamlReader.XmlTreeBuildDefault(ParserContext pc, XmlReader reader, Boolean wrapWithMarkupCompatReader, XamlParseMode parseMode, Boolean etwTracingEnabled)
at System.Windows.Markup.XamlReader.Load(XmlReader reader)
at DnD.DropTargetBase.ExtractElement(IDataObject obj) in C:\WPF research lab\DragDrop\DragDrop\DragDropManager\DropTargetBase.cs:line 61
InnerException: System.ArgumentException
Message=”Cannot register duplicate Name ‘_button1′ in this scope.”
Source=”PresentationFramework”
StackTrace:
at System.Windows.NameScope.RegisterName(String name, Object scopedElement)
at System.Windows.Markup.BamlRecordReader.DoRegisterName(String name, Object element)
at System.Windows.Markup.BamlRecordReader.ReadPropertyRecordBase(String attribValue, Int16 attributeId, Int16 converterTypeId)
InnerException:
Hi This is Krishna..
i tried your post it is working but i want to drag the dynamicaly created controls
it is not working for that and i too dnt know how to bind those controls to this.
Can u have any example which works for me?