OLE Drag and Drop Overview
- 10 minutes to read
The most flexible way to implement drag and drop operation when using the vertical grids (VGridControl and PropertyGridControl) is to make use of OLE drag and drop. This can be implemented by using several control members that are inherited from the Control class. This topic explains the basics of using OLE drag and drop technology and provides simple examples. Examples of using a VGridControl as the source or target for drag and drop operations can be found in the VerticalGrid as the Source of Drag and Drop and VerticalGrid as the Target of Drag and Drop topics.
Implementing the Drag And Drop Source
The drag and drop operation’s source must do the following:
- Initiate dragging in response to certain user actions. At this point, the source control must also specify the data to be dragged and whether this data can be copied, moved or both.
- Remove the dragged data from the control if the target control specified that data selected is moved, not copied. If data is copied, the source control doesn’t have to perform any actions when dragging finishes.
Usually, dragging is initiated by the source control’s MouseDown or MouseMove event handlers. This means you can use the MouseDown event to store the cursor’s clicked position. The MouseMove event handler must then check if the cursor’s offset position from the start point is greater than a predefined distance. If so, drag and drop needs to be initiated. To start a drag and drop operation, you need to call the DoDragDrop method which is inherited from the Control class. This method takes two parameters. The first sets the data to drag and the second specifies the drag and drop operations that can be performed. These operations are listed in the DragDropEffects enumeration. Note that usually, you will only need to use two possible effects - either DragDropEffects.Move or DragDropEffects.Copy. If you want to allow both operations, you need to set a bitwise combination of these values as the parameter for the DoDragDrop method.
The DoDragDrop method returns control after the drag and drop operation completes. You may inspect this method’s return value to determine whether data has been copied or moved. If the data has been moved, you will need to remove it from the source control.
The example below shows how to make a ListBox control a source for drag and drop operations. The MouseDown event is handled to initiate dragging. It determines the item located underneath the mouse cursor and this item’s text is passed to the DoDragDrop method as a parameter. Another parameter specifies that the data can be either copied or moved. If data has been moved as a result of drag and drop, the dragged item is then removed from the list box.
private void listBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
ListBox lb = sender as ListBox;
int itemIndex = lb.IndexFromPoint(e.X, e.Y);
if (itemIndex != -1) {
DragDropEffects effect = lb.DoDragDrop(lb.Items[itemIndex].ToString(), DragDropEffects.Copy | DragDropEffects.Move);
if (effect == DragDropEffects.Move)
lb.Items.RemoveAt(itemIndex);
}
}
If the control’s MouseDown event is handled as in the code above, you can drag items to other controls (which allow data to be dropped) or to other applications. For instance, you could drag items from your list box to a Microsoft Word document. If dragging while holding down the CTRL key, only the item’s text will be inserted into the target document. If the CTRL key is not pressed, then the data will be moved and the dragged item will be deleted from the list box as a result.
Implementing the Drag And Drop Target
The tasks to be performed by the drag and drop target are:
- Handle the dragging process. This means that the target control must specify which drag and drop operations are allowed, when an object is dragged over it.
- Handle dropping. This implies that the target control must modify its data when dropping onto it.
There are two events specifically designed to handle the dragging process, DragEnter and DragOver. The first fires when the mouse pointer enters the control’s client area provided that dragging is being performed. This event is likely to be used when a single operation can be performed upon dropping and dropping is allowed to take place anywhere within the control. The drop effect allowed must be set using the Effect event parameter.
The DragOver event fires repeatedly as an item is dragging over the target control. It must be used instead of the DragEnter event in the following cases:
- Data can be dropped only onto a specific area within the control. Since the DragOver event fires repeatedly, you can determine the control element currently located underneath the mouse pointer. Thus, you can allow drop operations for specific elements within a control. This cannot be performed using the DragEnter event since it fires only once.
- Several dropping operations are permitted. For instance, you may want to set the dropping effect with respect to the CTRL key’s state. This cannot be performed using the DragEnter event since a change in the CTRL key’s state after the mouse has entered the control’s area will not be noted as the event has already fired previously.
Note: The current coordinates for the mouse pointer and the key state can be obtained using the X, Y and KeyState parameters of the DragOver event.
In addition to the mouse coordinates and key state, the DragEnter and DragOver events also allow you to determine the data being dragged and the drag drop effects permitted by the source control. These can be obtained using the Data and AllowedEffects event parameters. The Data parameter can be used to determine if the dragged data can be converted to an appropriate type for insertion into the target control. For instance, you could prohibit dropping to a text box if image data is being dragged. The AllowedEffects parameter value must be used to determine if specific drop effects are permitted by the source, also note that if a specific operation is prohibited by the drag and drop source, it must not be permitted by the target as well.
As has been mentioned above, you need to use the Effect parameter of the DragEnter and DragOver events to specify the drop operation to perform. This parameter’s value affects the mouse cursor’s appearance. If dropping takes place, this value is returned by the DoDragDrop method so that the source control can perform any necessary actions.
Note: you can also make use of the DragLeave event which fires if dragging is being performed when the mouse pointer leaves the control’s area. This event can be handled in combination with the DragEnter event to display explanatory messages to end-users within the status bar which the DragLeave event handler would then clear, for instance.
If dropping is allowed by the DragOver or DragEnter event handlers, it can be handled using the DragDrop event. Handling dropping implies inserting the dragged data into the target control. For instance, if the drag and drop target is a list box control, you may add an item whose text is a string representation of the dragged data. Note that the DragDrop event enables you to identify the mouse pointer’s current coordinates via the X and Y parameters. This can then be used to insert dragged data into a specific position within the control. Considering the list box for instance, you could use these parameters to determine the item currently located under the mouse pointer and insert a new one before it.
The sample code below handles the DragOver and DragDrop events for a list box control to make it a drag and drop target. The DragOver event handler prohibits drop operations if the dragged data cannot be converted to text. If conversion is possible, the handler allows the operation and sets the drop effect with respect to the current key state and the effects allowed by the drag and drop source. The DragDrop event determines the item located under the mouse position and then inserts the dragged text before this item. If no item is under the cursor, the dragged text is appended to the end of the list.
private void listBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {
// prohibit dropping if data cannot be converted to text
if (!e.Data.GetDataPresent(DataFormats.Text)) {
e.Effect = DragDropEffects.None;
return;
}
// specifying the "Copy" effect if it is allowed by the source and the CTRL key is currently pressed
if ((e.KeyState == 9) && ((e.AllowedEffect & DragDropEffects.Copy) != 0)) {
e.Effect = DragDropEffects.Copy;
return;
}
// specifying the "Move" effect if it is allowed by the source
if ((e.AllowedEffect & DragDropEffects.Move) != 0)
e.Effect = DragDropEffects.Move;
}
private void listBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
ListBox lb = sender as ListBox;
// obtaining the index of the item located under the mouse cursor
int targetItemIndex = lb.IndexFromPoint(lb.PointToClient(new Point(e.X, e.Y)));
// obtaining the dragged data
string draggedData = e.Data.GetData(DataFormats.Text).ToString();
// inserting the dragged data into a proper position
if (targetItemIndex == -1)
lb.Items.Add(draggedData);
else
lb.Items.Insert(targetItemIndex, draggedData);
}
When events are handled in this manner, you can try to drag data from other controls or applications to the list box. For instance, you could drag data from a Microsoft Word document. Note though, that dropping images onto the list box will be prohibited. If dragging text without holding down the CTRL key, dragged data will be removed from the source document when dropping.
Important note: the AllowDrop property of a control must be set to true to allow users to drop objects onto it, otherwise the described events will not fire.