# Drag and Drop Question C#



## Kreij (Jun 4, 2009)

I've got two User Controls. One (ToolBox) contains a button, the other (Canvas) is empty.
I want to DnD (Copy) the button to the Canvas control.

In the ToolBox control I hook into the button's MouseDown event.

```
private void button1_MouseDown(object sender, MouseEventArgs e)
        {
            DoDragDrop((Button)sender, DragDropEffects.Copy);
        }
```

Then in the Canvas control I verify it's a button being dragged and perform the drop.

```
private void Canvas_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(Button))) e.Effect = DragDropEffects.Copy;
            else e.Effect = DragDropEffects.None;
        }

        private void Canvas_DragDrop(object sender, DragEventArgs e)
        {
            Canvas destination = (Canvas)sender;
            destination.Controls.Add((Button)e.Data.GetData(typeof(Button)));
        }
```

This should, by my estimations, make a copy of the button on the canvas.
However, what happens is the button is removed from the ToolBox control and placed on the Canvas.

Any thoughts as to why this is happening?


----------



## FordGT90Concept (Jun 4, 2009)

Ahhaha, the damn "copy by value" instead of "by reference" strikes again! 

Try a deep copy (deserialize).  Lemme find the code...


```
/// <summary>
        /// Performs a basic deep copy.
        /// 
        /// By: The Janitor
        /// From: http://weblogs.asp.net/gunnarpeipman/archive/2007/10/07/net-and-deep-copy.aspx
        /// </summary>
        public static T DeepCopy<T>(T obj)
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            T retval = (T)bf.Deserialize(ms);
            ms.Close();
            return retval;
        }
```

I've used that a few times.  It works great.

Do something like...

```
private void Canvas_DragDrop(object sender, DragEventArgs e)
        {
            Canvas destination = (Canvas)sender;
            destination.Controls.Add(DeepCopy<Button>(e.Data.GetData(typeof(Button))));
        }
```


----------



## Kreij (Jun 4, 2009)

Well, then what's the point of using the DragDropEffects.Copy enumeration (which is supposed to tell the framework to "Copy" the data, not move it) if you have to make your own (deserialized) copy?


----------



## FordGT90Concept (Jun 4, 2009)

I think that enumerator is just to tell the mouse to show the [+] symbol.  It doesn't actually perform a copy:
http://msdn.microsoft.com/en-us/library/system.windows.forms.dragdropeffects.aspx


The full DoDragDrop page:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.dodragdrop.aspx


----------



## Kreij (Jun 4, 2009)

Hmmm ... in order to stop the compiler from fussing, I had to cast the data to a button before feeding it into DeepCopy.


```
destination.Controls.Add(DeepCopy<Button>((Button)e.Data.GetData(typeof(Button))));
```

The button stays in the ToolBox now, but no button is added to the canvas.
I tried casting re-casting the output from DeepCopy to a button, but that did not work either ...

```
destination.Controls.Add((Button)DeepCopy<Button>((Button)e.Data.GetData(typeof(Button))));
```

I'll have to play with it. Thanks for the DeepCopy code, FordGT, that's always good to know.


----------



## FordGT90Concept (Jun 4, 2009)

Try it on here instead:

```
private void button1_MouseDown(object sender, MouseEventArgs e)
        {
            DoDragDrop(DeepCopy<Button>((Button)sender, DragDropEffects.Copy));
        }
```
That'll send the deserialized copy to the DoDragDrop.  If that doesn't work, you'll have to sort out what code is actually supposed to perform the copy and put it there.  Maybe that's just it: you don't have any code to copy it yet, just handle the drag n' drop?


I wasn't certain the cast would be necessary so I removed it in my example.  Bad move on my part. :x


I should be in bed.


----------



## Kreij (Jun 4, 2009)

This has become a MAJOR challenge 
The Button class is not Serializable so the BinaryFormatter throws an exception when you it gets to the "bf.serialize(ms, obj);" line.

I am looking at deriving a class from Button that uses the IserializableSurrogate interface, but that is not a trivial task.
All of the base Button properties have have to be written into the derived class to be serializable too. 

I am becoming an expert on serialization working on this. lol


----------



## FordGT90Concept (Jun 5, 2009)

Blah, I forgot about that.  I've only used that on classes I authored so I could go through and make everything serializable...

The other way to do it would be to make a second, new Button, and copy all the important data over (like .Text).  That way, you're not copying the class (and thus the serializable information), you're just copying some of the data points inside.

e.g.

```
private Button CopyButton(Button b)
{
  Button output = new Button();
  output.Text = b.Text;
  return output;
}
```

I wish it was easier to override the default memory action.  When the compiler decides to go by ref when by value was intended, it creates a lot of headaches as you can see.


----------



## Kreij (Jun 5, 2009)

I did get it working yesterday by using a more or less "fake" drag and drop (on drop create new button) by just ignoring the data that the DnD was using and doing a new. That, however, doesn't really help me as after the user adds controls to the Canvas I will need to serialize that also, which would leave me in the same position of trying to figure out how to serialize buttons. I'll just use another approach (create a different, serializable class).

This is because these classes (ie. Button) inherit MarshalByRef.
It's too bad they did not have these classes inherit MarshalByValue too, just to make life a little easier.
Supposedly you can have a class inherit both by using the [Serializable] attribute, but I could not get that to work with a new derived class. Now if I had all of the source code to these classes ..


----------



## FordGT90Concept (Jun 5, 2009)

Heh, yeah.  That's really unfortunate.  Looks like you have a lot of work ahead of you.


----------



## Kreij (Jun 5, 2009)

FordGT90Concept said:


> Heh, yeah.  That's really unfortunate.  Looks like you have a lot of work ahead of you.



Yeah, and this project is just for fun while I am waiting for testing feedback on my real work project.


----------

