Drag-and-drop is everywhere. Everywhere but probably not in your own applications! Possibly that your are thinking that it is too hard to implement or that no-one uses this kind of feature. But if look how your users are working with other applications, you will find them using drag-and-drop intuitively. Why don't you give them this boost of performance?
In this column, I will show you how to implement this feature to drag within your application and even between your application and other existing applications.
Basics
The drag-and-drop feature is very much like the cut-and-paste feature. You take the content of a source to copy it into a target.
The cut-and-paste feature uses the Clipboard during the operation while the drag-and-drop uses a DataObject object (which is nothing more then a private clipboard).
If you ever implemented drag-and-drop with VB6, you surely remember that there were two (2) kinds of dragging: Controls (using the DragMode property) and Contents (using the OLEDragMode property). The method I’ll show you here is the equivalent of the content’s drag-and-drop feature.
First example: Dragging text
This first example will let you drag-and-drop text between 2 textboxes on a form. You first need to add 2 textbox controls to a form. You must set the AllowDrop property of all textbox controls to True to let them receive the drop notification.
Figure 1: The sample application.
You can then copy this first snippet of code that starts the drag operation.
Private Sub TextBox_MouseMove( _ ByVal sender As Object, ByVal e As MouseEventArgs) _ Handles TextBox1.MouseMove, TextBox2.MouseMove 'Nothing to do if no mouse button is pressed. If e.Button = 0 Then Exit Sub 'Get a reference to the current textbox control Dim ctlCurrent As TextBox = DirectCast(sender, TextBox) 'Nothing to do if the textbox is empty! If ctlCurrent.TextLength = 0 Then Exit Sub 'Nothing to do if we are still inside the control's borders. If e.X >= 0 AndAlso e.X < ctlCurrent.Width AndAlso _ e.Y >= 0 AndAlso e.Y < ctlCurrent.Height Then Exit Sub 'If we get here, it means that the mouse is ' being dragged outside the control. 'Store the text to be drag into a DataObject object Dim objDO As New DataObject If ctlCurrent.SelectionLength = 0 Then objDO.SetData(DataFormats.Text, ctlCurrent.Text) Else objDO.SetData(DataFormats.Text, ctlCurrent.SelectedText) End If 'Starts the drag operation Dim effect As DragDropEffects = _ DragDropEffects.Copy Or DragDropEffects.Move effect = ctlCurrent.DoDragDrop(objDO, effect) 'This portion of code will run after the code has been dropped. 'Delete the (selected) text if it was a move. If effect = DragDropEffects.Move Then If ctlCurrent.SelectionLength = 0 Then ctlCurrent.Text = "" Else ctlCurrent.SelectedText = "" End If End If End Sub
The DragEnter event can be used to change the cursor effect depending on the control that is being entered and the content of the DataObject.
Private Sub TextBox_DragEnter( _ ByVal sender As Object, ByVal e As DragEventArgs) _ Handles TextBox1.DragEnter, TextBox2.DragEnter 'Check the format of the data being dropped. If e.Data.GetDataPresent(DataFormats.Text, True) Then 'Checks if the CTRL key is held If CBool(e.KeyState And 8) Then 'Display the copy cursor. e.Effect = e.AllowedEffect And DragDropEffects.Copy Else 'Display the move cursor e.Effect = e.AllowedEffect And DragDropEffects.Move End If Else 'Display the no-drop cursor. e.Effect = DragDropEffects.None End If End Sub
Private Sub TextBox_DragDrop( _ ByVal sender As Object, ByVal e As DragEventArgs) _ Handles TextBox1.DragDrop, TextBox2.DragDrop 'Check if data is present If Not e.Data.GetDataPresent(DataFormats.Text, True) Then Exit Sub 'Determine if it is a copy or move operation If CBool(e.KeyState And 8) Then ' Display the copy cursor. e.Effect = DragDropEffects.Copy Else e.Effect = DragDropEffects.Move End If 'Get a reference to the current textbox control Dim ctlCurrent As TextBox = DirectCast(sender, TextBox) 'Paste the text to drop ctlCurrent.SelectedText = e.Data.GetData(DataFormats.Text).ToString End Sub
To convince you that you did a good job, try to drag-and-drop text between your textboxes and Word. It should be working as well.
Second example: Dragging a picture
Dragging images between Picture controls is not really different from dragging text between TextBox controls. It is simply a matter of type of data. One strange thing (a bug or a feature – I don’t know) is that the AllowDrop property doesn’t appear into the Properties dialog. You have to set it by code (in the Form_Load event for example) like this:
Private Sub Form1_Load( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load PictureBox1.AllowDrop = True PictureBox2.AllowDrop = True End Sub
Third example: Dragging filename from the Windows Explorer
This example will let a listbox receive a filename dragged from the Windows Explorer. Once you have the filename and path in your application, you can do whatever you want it!
To do this, add a ListBox control to your form and don’t forget to set it’s AllowDrop property to True. Then you need this code:
Private Sub ListBox1_DragEnter( _ ByVal sender As Object, ByVal e As DragEventArgs) _ Handles ListBox1.DragEnter If e.Data.GetDataPresent(DataFormats.FileDrop) Then e.Effect = DragDropEffects.All End If End Sub Private Sub ListBox1_DragDrop( _ ByVal sender As Object, ByVal e As DragEventArgs) _ Handles ListBox1.DragDrop If e.Data.GetDataPresent(DataFormats.FileDrop) Then Dim MyFiles() As String Dim i As Integer ' Assign the files to an array. MyFiles = e.Data.GetData(DataFormats.FileDrop) ' Loop through the array and add the files to the list. For i = 0 To MyFiles.Length - 1 ListBox1.Items.Add(MyFiles(i)) Next End If End Sub
Other examples: ListViews & TreeViews
The downloadable demo also includes code that implements the drag-and-drop feature between 2 ListViews and between 2 TreeViews.
The main difference with these controls is that they raise the ItemDrag event as soon as the user starts to drag a node. If you look at the code, you will also discover the there are no values into the DataFormats enum that fits nodes. For this reason, we use overloaded GetDataPresent and GetData methods passing string to see what’s being dragged.
Conclusion
A bit of code to write and understand but it gives you great features. You surely some places where drag-and-drop would ease user’s experience.
I hope you appreciated the topic and see you next month.