One of the important features of Graphical User Interfaces (GUI) is drag and drop.
Using a mouse you can drag and drop a file from one location to another or you may drag a file and drop it onto an application to launch it.
However, not many developers take the effort to implement drag and drop functionality in their applications. While it does take considerable effort to implement, the support for drag and drop in your application will greatly increase its usefulness. In this article, I will show you how to implement drag and drop functionality in your Windows Forms application.
Drag and Drop Event Handlers
To understand how you can drag objects from one control onto another control, you need to become acquainted with a couple of event handlers. Consider the example of Figure 1 where you drag an image displayed in a PictureBox control to another PictureBox control.
On the control to be dragged (left PictureBox control):
The MouseDown/MouseMove event is probably a good starting point to load the data that is going to be dragged. In this case, you will copy the image stored in the left PictureBox control.
The QueryContinueDrag event allows you to know the outcome of the drag operation, i.e., whether the user eventually drops the item. If the dragging is a move operation and the user successfully executes it, you may need to remove the image on the left PictureBox control.
You can call the DoDragDrop() method either in the MouseDown or the MouseMove event.
The control constantly fires the GiveFeedBack event during the drag operation. You can handle this event if you wish to modify the appearance of the mouse pointer.
On the control to be dropped upon (right PictureBox control):
When the mouse enters the control to be dropped upon, the control fires the DragEnter event. This is usually the event that you need to service to change the mouse pointer to reflect the action it is performing (such as copy, move, etc). You can also modify the appearance of the control so that it is obvious to the user that the control is a drop target.
When the mouse hovers over the control to be dropped upon, the control fires the DragOver event. The control fires this event continuously as long as the mouse is over the target control. You can either use this event or the DragEnter event to change the appearance of the mouse pointer.
When the mouse leaves the control to be dropped upon, the control fires the DragLeave event. You usually service this event if you need to modify the appearance of the target control to reflect that it is a drop target.
When the mouse drops over the control to be dropped upon, the control fires the DragDrop event. In this event you can modify the target control so that it accepts the dropped item. In the above example, you will load the right PictureBox control with the image that the user drags from the left PictureBox control.
Note that not all controls support the entire set of events just described. For example, the RichTextBox control does not support the DragOver event. In this case, you will have to use other supported events to detect drag and drop, such as the DragEnter event.
Drag and Drop Text
I’ll now create a Windows Forms application so that you can examine how you can implement drag and drop. Using Visual Studio 2005, create a new Windows Forms application and name it DragAndDrop. For this section, I’ll show you how to drag and drop some text into a TextBox control.
For most controls, you can set the AllowDrop property in the Properties window during design time. However, some controls (such as the PictureBox control) do not expose this property in the Properties window. As such, you need to dynamically set them in code (note that IntelliSense will not show the AllowDrop property).
On the default Form1, populate it with a TextBox control and set its properties as follows (Figure 2):
Switch to the code behind of Form1 and declare the following constant:
Public Class Form1 Const CtrlMask As Byte = 8
In the Form1_Load event, set its AllowDrop property to True:
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load '---set the control to allow ' drop--- TextBox1.AllowDrop = True End Sub
The next event to service is the DragEnter event. As mentioned earlier, the control fires this event when you drag something into the TextBox control. Here, you will determine if the operation is copy or move, and then set the mouse pointer accordingly. To check for this special keystroke, you use the KeyState property together with a Control Mask (defined as a byte with a value of 8). In addition, you will also change the border style of the TextBox control to FixedSingle so that it serves as a visual cue to the user (Listing 1).
You can now press F5 to test the application. Figure 3 shows the mouse pointer when a user performs a move (top of the figure) and a copy (bottom of the figure) operation on the TextBox control. To perform a copy operation, simply hold the CTRL key when dragging your mouse.
Drag and Drop Images
In the previous section you saw how to drag and drop text into a TextBox control. In this section, you will learn how to drag and drop images using a PictureBox control.
Using the same project, drag and drop a PictureBox control onto the default Form1 (Figure 5).
In the Form1_Load event, set the PictureBox control with the properties as shown below (Listing 3).
As usual, service the DragEnter event so that you can change the mouse pointer appropriately when the mouse hovers over the PictureBox control. The only difference this time is that you check if the data to be dropped onto the PictureBox control is of type image (Listing 4).
For the DragDrop event, you will first verify that the dropped object is of type image and then proceed to set the PictureBox control to display the dropped image (Listing 5).
Lastly, for the DragLeave event, change the border style of the PictureBox back to its original:
Private Sub PictureBox1_DragLeave( _ ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles PictureBox1.DragLeave '---set the borderstyle back to ' its original--- PictureBox1.BorderStyle = _ BorderStyle.FixedSingle End Sub
Press F5 to test the application. You can drag an image from Microsoft Word and drop it onto the PictureBox control, which will then display the image. Interestingly, dragging and dropping an image from WordPad does not cause the PictureBox control to display the image. I will explain this in a short while.
Now I’ll write some code so that you can drag the image displayed in the PictureBox control onto somewhere else, such as another control or Microsoft Word (or WordPad).
First you'll handle the MouseDown event handler. The control fires this event when the user clicks the image in the PictureBox control:
Private Sub PictureBox1_MouseDown( _ ByVal sender As Object, _ ByVal e As System.Windows.Forms. _ MouseEventArgs) _ Handles PictureBox1.MouseDown If PictureBox1.Image IsNot _ Nothing Then PictureBox1.DoDragDrop( _ PictureBox1.Image, _ DragDropEffects.Move Or _ DragDropEffects.Copy) End If End Sub
Here, you use the DoDragDrop() method of the PictureBox control to copy the image displayed in the PictureBox control. The second parameter of this method indicates the type of drag operations that can occur (in this case it is either a move or copy operation).
That’s it! You can now drag and drop the image displayed in the PictureBox control to another control. Again, ironically you can drag the image onto WordPad, but not into Microsoft Word.
Let me recap what happened:
You can drag a picture from Microsoft Word and drop it onto the PictureBox control. But you cannot drag and drop from WordPad.
When you try to drag the image from the PictureBox control onto Word, it does not accept the picture. But you can drag and drop the same image onto WordPad.
To understand why an image can be dropped from Word but not from WordPad, you should modify your application so that you can observe in detail the types of data that are being passed to the PictureBox control.
In the DragEnter event, add the line in bold. The GetFormats() method returns the type of data that is passed into the event (Listing 6).
You should set a breakpoint after the line just added so that you can observe the type of data being passed into the event. Press F5 to debug the application and drop an image from Word onto the PictureBox control. Figure 6 shows the data type of the image dragged and dropped from Word.
Here you can observe that one of the formats is bitmap, and hence you can safely convert the data into a bitmap image and display it in the PictureBox control. In contrast, if you drag and drop an image from WordPad, its corresponding type for the image is shown in Figure 7.
This time round, the control does not represent the image data in the bitmap format. Instead, the control passes it in the Rich Text Format (RTF).
To ensure that the PictureBox control can accept images dragged and dropped from WordPad, you need to modify the DragEnter event (as shown in bold) (Listing 7).
In addition, you also need to modify the DragDrop event so that you can write your custom code to deal with the particular data format (Listing 8).
In my example above, I simply write the data of the image (as RTF) to the console window (Figure 8). To display the image in the PictureBox control, you will have to write your own code to extract the image data.
Move versus Copy
The previous example shows how you can copy or move an image from the PictureBox control. In a typical move operation, after copying the image to another control/location, you need to remove the original image. So how do you know when a drop operation has completed? The answer lies in the QueryContinueDrag event.
Let’s add another PictureBox control to Form1 so that Form1 now looks like Figure 9. I will demonstrate how you can move an image (by drag and drop) from PictureBox1 to PictureBox2.
Configure PictureBox2 in the Form1_Load event as follows (Listing 9).
Code PictureBox2 to allow for dropping (Listing 10).
You should remove the image in PictureBox1 after the user has moved it to PictureBox2. To do this, you need to service the QueryContinueDrag event of PictureBox1. The control fires this event when you drag and drop an image from PictureBox1. Here you determine if the operation is a move, and if it is, you will delete the image from PictureBox1 (Listing 11).
You can now test to see if it works. Press F5 in Visual Studio 2005 and drag and drop an image onto PictureBox1. Then, drag the image in PictureBox1 and drop it onto PictureBox2. You can notice that the image in PictureBox1 is now gone. In contrast, note that if you instead perform a copy operation (by holding down the CTRL key); the control merely copies the image and does not remove it.
Note that using the QueryContinueDrag event to remove an item that a user has moved is not a foolproof method. If you abort the move operation (such as dropping the image outside PictureBox2), the control will still remove the picture. In other words, using the QueryContinueDrag event, you have no idea where the user moved (or dropped) the item (or if the user aborted the operation).
Drag and Drop Files
A very common operation performed in a Windows application is dragging and dropping files onto applications. For example, you drag and drop files onto folders or perhaps you drag music files onto Windows Media player so that you can play them immediately.
Let me show you how to modify your application so that users can drag an image file from Windows Explorer and drop it onto the PictureBox control. First, modify the DragEnter event (Listing 12).
The data type for a file that is dragged from the Windows Explorer is FileDrop, and hence you check for this data type in the DragEnter event handler.
Next, modify the DragDrop event so that you can manually open up the image file and display its content in the PictureBox control (Listing 13).
That’s it! You can now drag an image file from Windows Explorer and drop it onto the PictureBox control and view its content. Note that in this particular implementation, users can drop one or more files onto the PictureBox control. What I have done is to display each photo one by one with a two-second interval.
Implementing Drag and Drop for Custom Objects
Most Windows Forms controls support the set (or subset) of events that I described in this article for drag and drop operations. However, what happens if the control you want to enable for drag and drop does not support the list of events that I have just described? A good example is the Windows Media Player ActiveX control. You might want to embed the Windows Media Player control in a Windows application so that users can simply drag and drop media files onto it to play. The Windows Media Player ActiveX control by itself does not support events like DragEnter and DragDrop, and hence there is no easy way to implement drag and drop.
A workaround is to wrap the ActiveX control using a User control. First, add a new User Control item (right-click the project name in Solution Explorer and select Add > New Item… > select User Control) to the existing project. Name the file as MediaPlayer.vb.
Right-click the Toolbox and select Choose Items…. In the Choose Toolbox Items dialog box, click the COM Components tab and check the Windows Media Player object (Figure 10). Click OK to add the Windows Media Player control onto the Toolbox.
Drag the Windows Media Player control from the Toolbox and drop it onto the MediaPlayer.vb design surface (Figure 11).
In the code behind of MediaPlayer.vb, code the following:
Public Class MediaPlayer Private _URL As String Public Property URL() As String Get Return _URL End Get Set(ByVal value As String) _URL = value AxWindowsMediaPlayer1. _ URL = _URL End Set End Property End Class
Essentially you expose the URL property to let the user of this control set the URL of the media file to play.
Right-click the project name in Solution Explorer and select Build. The MediaPlayer control should now appear in the toolbox (Figure 12).
Drag and drop the MediaPlayer user control onto Form1 (Figure 13).
Switch to the code behind of Form1 and handle the DragEnter event of the MediaPlayer user control (Listing 14).
Finally, handle its DragDrop event so that you can play the media file dropped by the user (Listing 15).
Note that since the user can drop multiple files onto the control, you will only load the first file using the MediaPlayer control. Figure 14 shows the MediaPlayer control hosted in a Windows Form playing the file dropped onto it.
Dragging and Dropping Custom Objects
So far in this article I’ve shown you how to use the various data types as specified in the DataFormats class: Bitmap, CommaSeparatedValue, Dib, Dif, EnhancedMetafile, FileDrop, Html, Locale, MetafilePict, OemText, Palette, PenData, Riff, Rtf, Serializable, StringFormat, SymbolicLink, Text, Tiff, UnicodeText, and WaveAudio. What happens if you want to drag and drop data of a specific type? For example, you might want to drag an item in a ListView control. In this case, the DragEnter event will look something like this:
If (e.Data.GetDataPresent _ ("System.Windows.Forms. _ ListViewItem()")) Then '---determine if this is a copy '---or move--- If (e.KeyState And CtrlMask) = CtrlMask Then e.Effect = DragDropEffects.Copy Else e.Effect = DragDropEffects.Move End If
The MouseDown event handler will now look like this:
Control.DoDragDrop(New _ DataObject("System.Windows.Forms. ListViewItem()", _ Items), DragDropEffects.Move Or _ DragDropEffects.Copy)
It is not really difficult to implement drag and drop functionality in your Windows application. All you need is to understand the type of data you want to support and make the necessary provisions for dealing with that particular data type.