Drag-and-Drop
Drag-and-drop operations aren't quite as common today as they were a few years ago, because programmers have gradually settled on other methods of copying information that don't require holding down the mouse button (a technique that many users find difficult to master). For example, a drawing program is likely to use a two-step operation (select an object, and then draw it on) rather than a single drag-and-drop operation. Programs that do support drag-and-drop often use it as a shortcut for advanced users, rather than a standard way of working.
Drag-and-drop is also sometimes confused with the ability to "drag" a picture or piece of user interface around a window. This "fake" drag-and-drop is useful in drawing and diagramming applications (including the drawing application developed in 13), but it needs to be coded manually. In this section, you will learn about both types of dragging operations.
"Fake" Drag-and-Drop
True drag-and-drop is a user-initiated way to exchange information between two controls. You don't need to use drag-and-drop events to create objects that the user can move around the form (Figure 4-18). For example, consider the following program that allows a user to click on a picture box, drag it around, and release it somewhere else on the form.

Figure 4-18: Dragging a control around
Conceptually, a control is being dragged and dropped, but all the logic takes place in the appropriate mouse handling events. A Form level isDragging variable keeps track of when fake drag-and-drop mode is currently switched on.
// Keep track of when fake "drag and drop" mode is enabled.
private bool isDragging = false;
// Store the location where the user clicked the control.
private int clickOffsetX, clickOffsetY;
// Start dragging.
private void lblDragger_MouseDown(System.Object sender,
System.Windows.Forms.MouseEventArgs e)
{
isDragging = true;
clickOffsetX = e.X;
clickOffsetY = e.Y;
}
// End dragging.
private void lblDragger_MouseUp(System.Object sender,
System.Windows.Forms.MouseEventArgs e)
{
isDragging = false;
}
// Move the control (during dragging).
private void lblDragger_MouseMove(System.Object sender,
System.Windows.Forms.MouseEventArgs e)
{
if (isDragging == true)
{
// The control coordinates are converted into form coordinates
// by adding the label position offset.
// The offset where the user clicked in the control is also
// accounted for. Otherwise, it looks like the top-left corner
// of the label is attached to the mouse.
lblDragger.Left = e.X + lblDragger.Left - clickOffsetX;
lblDragger.Top = e.Y + lblDragger.Top - clickOffsetY;
}
}
There are three components that factor into the position calculation:
The e.X and e.Y parameters provide the position of the mouse over the control, where (0,0) is the top-left corner of the control.
The lblDragger.Left and lblDragger.Top properties give the position between the top-left corner of the control, and the top-left corner of the form.
The ClickOffsetX and ClickOffsetY variables give the position between the control's top-left corner and where the user actually clicked to start dragging. By taking this into account, the label acts as though it is "glued" to the mouse at that point.
Authentic Drag-and-Drop
Real drag-and-drop operations are quite a bit different. Essentially, they work like this:
The user clicks a control and holds the mouse button down. At this point, some information is set aside and a drag-and-drop operation begins.
The user moves the mouse over another control. If this control can accept the current type of content (for example, a picture or text) the mouse cursor changes to a special drag-and-drop icon. Otherwise, the mouse cursor becomes a circle with a line drawn through it.
When the user releases the mouse button, the control receives the information, and decides what to do with it.
Unlike our fake drag-and-drop example, a real drag-and-drop operation can easily take place between controls, or even two different applications, as long as the drag-and-drop contract is followed.
The example program below uses drag-and-drop to take a picture from a label control and draw it onto a picture box control. The actual drawing operation uses GDI+ methods that you examine in more detail later in this book. All other details are generic parts of any drag-and-drop application (Figure 4-19). You'll find the complete code with the samples for this chapter under the project name AuthenticDragAndDrop.

Figure 4-19: A sample drag-and-drop application
The first step is to configure the picture box control to accept dropped information.
picDrawingArea.AllowDrop = true;
To start the drag-and-drop, you can use the DoDragDrop() method of the source control. In this case, it is one of three labels. Dragging is initiated in the MouseDown event for the label.
private void lbl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Label lbl = (Label)sender;
lbl.DoDragDrop(lbl.Image, DragDropEffects.Copy);
}
The same event handler handles the MouseDown event for each label. In the event handler, the generic sender reference (which points to the object that sent the event) is converted into a label. Then, a drag-and-drop copy operation is started. The information associated with this operation is the image from the label control.
To allow the picture box to receive information, you need to verify that the information is the correct type in the DragEnter event, and then set a special event argument (e.Effect). DragEnter occurs once when the mouse moves into the bounds of the control.
private void picDrawingArea_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
The last step is to respond to the information once it is dropped, by handling the DragDrop event. You can do anything you want with the dropped information. In the current example, a GDI+ drawing operation is started (although it could make just as much sense to create a new object in that location and set its Image property).
private void picDrawingArea_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
Graphics g = picDrawingArea.CreateGraphics();
g.DrawImage((Image)e.Data.GetData(DataFormats.Bitmap),
new Point(e.X - this.Left - 12, e.Y - this.Top - 30));
}
Note that the event handler provides screen coordinates, which must be converted into the appropriate coordinates for the picture box.
Practically, you can exchange any type of object through a drag-and-drop operation. However, while this free-spirited approach is perfect for your applications, it isn't wise if you need to communicate with other applications. If you want to drag-and-drop into other applications, you should use data from a managed base class (like String or Image), or an object that implements ISerializable or IDataObject (which allows .NET to transfer your object into a stream of bytes, and reconstruct the object in another application domain).