Chapter 35. Providing Drag and Drop

In some ways, drag and drop performs the same task as the clipboard. Both enable one application to give data to another. The difference is that the clipboard saves data for later delivery, whereas drag and drop delivers the data immediately and is done.

In this lesson, you learn how to add drag and drop to your program so it can interact with other applications.

UNDERSTANDING DRAG AND DROP EVENTS

There are two participants in a drag and drop operation: a drag source and a drop target.

  • The drag source initiates a drag — for example, when you right-click it. It determines what data is in the drag and what kinds of operations are allowed on the drag, such as a copy or move.

  • The drop target is a potential recipient of a drag's data. When the drag moves over it, the target can decide whether it can accept the data in an offered operation such as copy or move.

To handle all of the potential interactions among the drag source, the drop target, and the user, you can use several event handlers. Some of these events occur in the drag source and others occur in the drop target.

Table 35-1 summarizes the key drag source events.

Table 35.1. TABLE 35-1

EVENT

PURPOSE

GiveFeedback

The drag has entered a valid drop target. The source can indicate the type of drop allowed. For example, it might allow Copy if the target is a Label and allow Move or Copy if the target is a TextBox.

QueryContinueDrag

The keyboard or mouse button state has changed. For example, the user may have pressed or released the [Ctrl] key. The drag source can determine whether to continue the drag, cancel the drag, or drop the data immediately.

The drop target has more events than the drag source. The drag source merely provides data. The drop target can provide a lot more interaction to tell the user what it can do with the data.

Table 35-2 describes the events received by a drop target when data is dragged over it.

Table 35.2. TABLE 35-2

EVENT

PURPOSE

DragEnter

The drag is entering the target. The target can examine the type of data available and set e.Effect to indicate the types of drops it can handle. It can also display some sort of highlight to tell the user that it can accept the data and where it might land.

DragLeave

The drag has left the target. The target should remove any highlighting or other hints that it displayed in DragEnter.

DragOver

The drag is over the target. This event continues to fire a few times per second until the drag leaves. For example, the target could change its appearance to show exactly where the data would land if dropped. It can also check things such as the keyboard state — for example, it might allow a Copy if the [Ctrl] key is pressed, and a Move otherwise.

DragDrop

The user dropped the data on the target, so the target should process it.

STARTING A DRAG

Starting a drag is fairly easy. First create an instance of the DataObject class to indicate the type of data being dragged and to hold the data itself. Then simply call a control's DoDrag method, passing it the DataObject.

The DragSource example program (available in this lesson's code download) uses the following code to start dragging text when you press the right mouse button down over its lblDrag control:

' Start a drag.
Private Sub lblDrag_MouseDown(ByVal sender As System.Object,
 ByVal e As System.Windows.Forms.MouseEventArgs) Handles lblDrag.MouseDown
    ' If it's not the right mouse button, do nothing.
    If e.Button <> MouseButtons.Right Then Return

    ' Make the data object.
    Dim data As New DataObject(DataFormats.Text, lblDrag.Text)

    ' Start the drag allowing only copy.
    lblDrag.DoDragDrop(data, DragDropEffects.Copy)
End Sub

The code first checks whether the right mouse button is pressed, and exits if it is not. It then creates a DataObject. It passes the object's constructor the value DataFormats.Text to indicate that it will hold text data, and the text that the object should hold.

Finally, the code calls the Label control's DoDrag method, passing it the DataObject and the value DragDropEffects.Copy to indicate that the drag allows only the copy operation.

This example doesn't bother with the GiveFeedback and QueryContinueDrag event handlers, so that's the extent of its participation in the drag.

Note

The DoDrag function returns a DragDropEffects value that indicates what the drop target did with the data. For example, if the function returns DragDropEffects.Move, then the user is performing a Move operation, so the drag source should remove the data from its application. For example, a file explorer such as Windows Explorer would remove the file from the source location and move it to the drop location.

Note that a drag is completely separate from the drop target. If a drop target can accept the data, it is free to do so. That means you don't need to wait until you read about the DropTarget example program described in the next section to test the DragSource program. You can test the program right now by using it to drag text data into Word, WordPad, or any other program that accepts dropped text. (Notepad doesn't know how to accept dropped text.)

CATCHING A DROP

Before a control can accept a drop, you must set its AllowDrop property to True. If AllowDrop is False, the control will not allow drops no matter what event handlers you create.

The only other thing a drop target must do is provide DragEnter and DragDrop event handlers.

The DragEnter event handler should examine the data available and set the event handler's e.Effect parameter to indicate whether it wants to allow the drop. The drag and drop system automatically changes the mouse cursor to indicate the kind of drop the target allows.

The DropTarget example program (available in this lesson's code download) uses the following DragEnter event handler:

' A drag entered. See if text is available.
Private Sub lblDrop_DragEnter(ByVal sender As Object,
 ByVal e As System.Windows.Forms.DragEventArgs) Handles lblDrop.DragEnter
    ' Allow text data.
    If e.Data.GetDataPresent(DataFormats.Text) Then
        ' Only allow the Copy operation.
        e.Effect = DragDropEffects.Copy
    End If
End Sub

This code checks whether the drag contains text data and, if it does, sets e.Effect to allow the Copy operation.

Note

The DragEnter event handler's e.Effect parameter has the value DragDropEffects.None by default, so you don't need to set it if you want to prevent a drop. In the DropTarget example program, if no text is available, the program doesn't allow any kind of drop operation.

The DragDrop event handler should use its e.Data parameter to see what data is available and to get it. It should then set e.Effect to indicate what operation it performed, such as Copy or Move so the drag source knows what happened to the data.

The DropTarget example program uses the following DragDrop event handler:

' Accept dropped data.
Private Sub lblDrop_DragDrop(ByVal sender As Object,
 ByVal e As System.Windows.Forms.DragEventArgs) Handles lblDrop.DragDrop
    ' Get the dropped data.
    If e.Data.GetDataPresent(DataFormats.Text) Then
        lblDrop.Text = e.Data.GetData(DataFormats.Text).ToString()

        ' Indicate that we copied.
        e.Effect = DragDropEffects.Copy
    End If
End Sub

This code checks for text data. If text is available, the code gets it and displays it in a label. It also sets e.Effect = DragDropEffects.Copy to tell the drag source that the target performed a Copy operation.

Note that accepting a drop is completely separate from the drag. If data is available in a format that your program can use, you are free to use it. In this case, that means you don't need to use the DragSource example program described in the previous section to test the DropTarget example program. You can also drag text from Word, WordPad, or any other program that knows how to start dragging text. (Notepad doesn't know how to start a drag.)

TRY IT

In this Try It, you elaborate on the DragSource and DropTarget example programs. You modify DragSource so it allows Copy or Move operations.

You make DropTarget perform Copy or Move operations depending on whether the [Ctrl] key is pressed during the drop. You also provide feedback if the user changes the state of the [Ctrl] key during the drag.

Note

You can download the code and resources for this Try It from the book's web page at www.wrox.com or www.vb-helper.com/24hourvb.html. You can find them in the Lesson35 folder of the download.

Lesson Requirements

In this lesson:

  • Copy the DragSource and DropTarget example programs into new directories.

  • In DragSource, allow Copy and Move operations. Check the result of DoDragDrop and if the operation was a Move, remove the text from the source Label control.

  • In DropTarget, make the DragEnter event handler allow Copy and Move operations.

  • In DropTarget, add a DragOver event handler. The value e.KeyState And 8 is nonzero if the [Ctrl] key is pressed. If [Ctrl] is pressed, allow Copy. If [Ctrl] is not pressed, allow Move.

  • In DropTarget, make the DragDrop event handler check the state of the [Ctrl] key just as DragOver does. If [Ctrl] is pressed, tell the drag source that the operation is a Copy. If [Ctrl] is not pressed, tell the drag source that the operation is a Move.

Hints

  • To make DragSource allow either Move or Copy operations, use DragDropEffects.Copy Or DragDropEffects.Move.

  • Similarly to make DropTarget allow either Move or Copy operations, use DragDropEffects.Copy Or DragDropEffects.Move.

  • Don't use the magic number 8; use a constant instead. What scope do you need to give the constant to enable the DragOver and DragDrop event handlers to see it?

Step-by-Step

  • Copy the DragSource and DropTarget example programs into new directories.

    1. This is straightforward.

  • In DragSource, allow Copy and Move operations. Check the result of DoDragDrop and if the operation was a Move, remove the text from the source Label control.

    1. Pass the DoDragDrop function the parameter DragDropEffects.Copy Or DragDropEffects.Move for the allowed operations.

    2. Check the result returned by DoDragDrop. If the result is DragDropEffects.Move, clear the Label control.

    3. The code should look something like this:

      ' Start a drag.
      Private Sub lblDrag_MouseDown(ByVal sender As System.Object,
       ByVal e As System.Windows.Forms.MouseEventArgs) _
       Handles lblDrag.MouseDown
          ' If it's not the right mouse button, do nothing.
          If e.Button <> MouseButtons.Right Then Return
      
          ' Make the data object.
          Dim data As New DataObject(DataFormats.Text, lblDrag.Text)
      
          ' Start the drag allowing only copy.
          If lblDrag.DoDragDrop(data, DragDropEffects.Copy Or
              DragDropEffects.Move) = DragDropEffects.Move _
          Then
              ' It's a move. Remove the data from here.
              lblDrag.Text = ""
          End If
      End Sub
  • In DropTarget, make the DragEnter event handler allow Copy and Move operations.

    1. In the DragEnter event handler, if text data is available, set e.Effect = DragDropEffects.Copy Or DragDropEffects.Move to allow both Copy and Move operations. The code should look something like this:

      ' A drag entered. See if text is available.
      Private Sub lblDrop_DragEnter(ByVal sender As Object,
       ByVal e As System.Windows.Forms.DragEventArgs) _
       Handles lblDrop.DragEnter
          ' Allow text data.
          If e.Data.GetDataPresent(DataFormats.Text) Then
              ' Only allow the Copy operation.
              e.Effect = DragDropEffects.Copy Or DragDropEffects.Move
          End If
      End Sub
  • In DropTarget, add a DragOver event handler. The value e.KeyState And 8 is nonzero if the [Ctrl] key is pressed. If [Ctrl] is pressed, allow Copy. If [Ctrl] is not pressed, allow Move.

    1. Add the DragOver event handler. If [Ctrl] is pressed, set e.Effect = DragDropEffects.Copy. If [Ctrl] is not pressed, set e.Effect = DragDropEffects.Move.

      ' The numeric code for Ctrl.
      Private Const KeyCtrl As Integer = 8
      
      ' Provide feedback. Allow Copy if Ctrl is pressed.
      ' Otherwise allow Move.
      Private Sub lblDrop_DragOver(ByVal sender As Object,
       ByVal e As System.Windows.Forms.DragEventArgs) _
       Handles lblDrop.DragOver
          ' See if the Ctrl key is pressed.
          If (e.KeyState And KeyCtrl) <> 0 Then
              ' The Ctrl key is pressed. Allow Copy.
              e.Effect = DragDropEffects.Copy
          Else
              ' The Ctrl key is not pressed. Allow Move.
              e.Effect = DragDropEffects.Move
          End If
      End Sub
  • In DropTarget, make the DragDrop event handler check the state of the [Ctrl] key just as DragOver does. If [Ctrl] is pressed, tell the drag source that the operation is a Copy. If [Ctrl] is not pressed, tell the drag source that the operation is a Move.

    1. Display the data as before.

    2. Determine whether Ctrl is pressed. If [Ctrl] is pressed, set e.Effect = DragDropEffects.Copy. If [Ctrl] is not pressed, set e.Effect = DragDropEffects.Move.

      ' Accept dropped data.
      Private Sub lblDrop_DragDrop(ByVal sender As Object,
       ByVal e As System.Windows.Forms.DragEventArgs) _
       Handles lblDrop.DragDrop
          ' Get the dropped data.
          If e.Data.GetDataPresent(DataFormats.Text) Then
              lblDrop.Text = e.Data.GetData(DataFormats.Text).ToString()
      
              ' See if the Ctrl key is pressed.
              If (e.KeyState And KeyCtrl) <> 0 Then
                  ' The Ctrl key is pressed. We did a Copy.
                  e.Effect = DragDropEffects.Copy
              Else
                  ' The Ctrl key is not pressed. We did a Move.
                  e.Effect = DragDropEffects.Move
              End If
          End If
      End Sub

Note

Please select Lesson 35 on the DVD to view the video that accompanies this lesson.

EXERCISES

  1. Copy this lesson's Try It (both the DragSource and DropTarget programs). Modify the DropTarget program in these ways:

    • Add a ListBox named lstFormats. In the program's DragEnter event handler, loop through the string array returned by e.Data.GetFormats and list the available formats in the ListBox.

    • In the DragEnter event handler, allow the Copy operation for the Text and FileDrop types of data.

    • Add a DragLeave event handler that clears formatsListBox.

    • In the DragDrop event handler, display text in a TextBox as before. If the dropped data is a FileDrop, it is an array of strings. Loop through the array and display the dropped filenames in a ListBox named lstFiles. Test this feature by dragging files from Windows Explorer onto the program.

  2. Copy the program you built for the Try It in Lesson 34 (or download Lesson 34's version from the book's web site). Add the capability to accept a dropped file list instead of only getting a file list from the clipboard.

    Hint: Don't forget to set the AllowDrop property to True.

    Hint: It would be nice to move the code that backs up the files into a new BackupFiles function so you could call it for a file list taken from the clipboard or from drag and drop. Unfortunately, the clipboard's file list is a StringCollection, but drag and drop's file list is an array of strings. Because they have different data types, you cannot make BackupFiles handle them both easily.

    To solve this problem, make BackupFiles take a filenames parameter of the nongeneric interface type IList. The clipboard data implements this interface, so you can simply pass it to BackupFiles. To pass the drag and drop data to BackupFiles, convert the file list to an array of strings, which also implements IList.

Note

You can find solutions to this lesson's exercises in the Lesson35 folder inside the download available on the book's web site at www.wrox.com or www.vb-helper.com/24hourvb.html.

EXERCISES
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset