65.9K
CodeProject is changing. Read more.
Home

DragData Demo

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (14 votes)

Sep 6, 2004

3 min read

viewsIcon

62846

downloadIcon

736

How to pass custom objects in a drag-and-drop operation.

Introduction

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 DragEventArgs.

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, 
                    System.Windows.Forms.MouseEventArgs e)
{
    MyClass myObject = new MyClass("TestObject");
    button1.DoDragDrop(myObject, DragDropEffects.Copy);
}

In the sample program, we initiate the drag from a MouseDown event. We instantiate the custom object, then pass it to DoDragDrop().

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, 
                      System.Windows.Forms.DragEventArgs e)
{
    bool dragObjectIsMyClass = 
              (e.Data.GetDataPresent(typeof(MyClass)) == true);
    if (dragObjectIsMyClass);
    {
        e.Effect = DragDropEffects.Copy;
    }
}

In this case, we're looking for an object of type MyClass. The 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 DragDropEffects 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, 
                                 System.Windows.Forms.DragEventArgs e)
{
    MyClass retrievedObject = (MyClass)e.Data.GetData(typeof(MyClass));
    textBox1.Text = retrievedObject.Name;
}

To extract the object, we call e.Data's 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.