(Print this page)

Drag and Drop in VB.Net
Published date: Sunday, February 1, 2004
On: Moer and Éric Moreau's web site

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
Be careful to list all the textbox controls you want to handle with this handler by adding them to the Handles clause (see the event declaration). The comments included should be enough to let you know what it is going.

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
Finally, the DragDrop event is used to manage the actual operation.
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
I concede that there are many lines here but considering that this code can handles all textboxes of a single form is not that bad! Didn’t VB6 do that alone?

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
Because doesn't change a lot from the previous example, I won't copy the complete code here. You can download the source code of this demo using the link at the bottom of this column to see the picture dragging in action.

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
When you look at the code, you see that it is, once again, much the same! Checking if the data is present in the appropriate format and retrieve it.

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.


(Print this page)