Drag-and-drop can be very frustrating, particularly when one wants to do something simple. The .NET Framework documentation example on drag-and-drop runs to six printed pages. The documentation on the
IDataObject interface is even more frustrating. But I won't get started on that...
I've been banging my head all afternoon, when all I really wanted to do was figure out a pretty simple task: How to pass a custom object as a
DragEventArgs property? It should be pretty simple, and it turns out it is.
Passing a custom object
Here's the problem: Say I have declared a class,
MyClass, and instantiated an object,
myObject, from it. I want to pass
myObject as the
Data property of the
DragEventArgs parameter that accompanies all Drag-and-Drop events.
You might ask why I want to go to all this trouble. Wouldn't it be simpler to set a member variable to the object and use that? If I can do that, that's great. But if I am dragging from one UserControl to another UserControl, each of them is going to need additional plumbing to handle the operation. Things are much simpler if I can simply pass the drag object as the
Data property of
It turns out that it's not at all difficult to do. The attached sample project shows how it's done. First, enable the
AllowDrop property in the drop target. Then, pass the drag object to
DragEventArgs in the
DoDragDrop() method of the control where the drag is initiated:
private void button1_MouseDown(object sender,
MyClass myObject = new MyClass("TestObject");
In the sample program, we initiate the drag from a
MouseDown event. We instantiate the custom object, then pass it to
Next, when we enter the control that will be our drop target, we test the
DragEventArgs data to see if it is of a type the target can accept. We use the
GetDataPresent() method to accomplish that task:
private void textBox1_DragEnter(object sender,
bool dragObjectIsMyClass =
(e.Data.GetDataPresent(typeof(MyClass)) == true);
e.Effect = DragDropEffects.Copy;
In this case, we're looking for an object of type
GetDataPresent() method takes a
System.Type argument, so we get the type of our class using
typeof(). If we find the correct type in the
e.Data property, then we set the
e.Effect property to a value from the
enum. This is the mechanism that allows the control to finally accept the drop. If we don't set this property, the target control will show the slash-circle 'not available' cursor, and the control won't accept the drop.
With the target control primed and ready, we make the drop. The target fires its
DragDrop event, which we use to extract the
MyClass object we passed in from the drag control earlier:
private void textBox1_DragDrop(object sender,
MyClass retrievedObject = (MyClass)e.Data.GetData(typeof(MyClass));
textBox1.Text = retrievedObject.Name;
To extract the object, we call
GetData() method, passing it the type of our custom object. The object is returned as a generic
object, so we need to cast it as a
MyClass object. Once that's done, we have full access to the object. In the sample project, we simply place the object's name in the target control.
All in all, pretty straightforward, and a more elegant solution than passing objects around among member variables. If you have any questions, post them here. I'll be back in the next week or so to answer any that have been posted.