# VBForums CodeBank > CodeBank - Visual Basic .NET >  Drag & Drop in Windows Forms

## jmcilhinney

C# version here.

I'm sure others have posted about this topic before but I'm sure another won't hurt.  I'll post various examples of drag & drop within the same control, between controls and between applications.

If you're interested in performing drag & drop operations in WinForms then I suggest that you read this and this at least.

I'll start with moving items between two ListBoxes, which is relatively simple.

1. Create a new WinForms application project.
2. Add two ListBoxes to the form.
3. Add the following code:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    'Allow data to be dropped on both ListBoxes.
    Me.ListBox1.AllowDrop = True
    Me.ListBox2.AllowDrop = True

    'Populate the ListBoxes.
    Me.ListBox1.Items.AddRange(New String() {"List 1, Item 1", _
                                             "List 1, Item 2", _
                                             "List 1, Item 3", _
                                             "List 1, Item 4", _
                                             "List 1, Item 5"})
    Me.ListBox2.Items.AddRange(New String() {"List 2, Item 1", _
                                             "List 2, Item 2", _
                                             "List 2, Item 3", _
                                             "List 2, Item 4", _
                                             "List 2, Item 5"})
End Sub

Private Sub ListBox_MouseDown(ByVal sender As Object, _
                              ByVal e As MouseEventArgs) Handles ListBox1.MouseDown, _
                                                                 ListBox2.MouseDown
    Dim source As ListBox = DirectCast(sender, ListBox)

    For index As Integer = 0 To source.Items.Count - 1
        'Test whether the mouse location is within an item
        If source.GetItemRectangle(index).Contains(e.Location) Then
            'The mouse was depressed on an item so allow a move operation.
            source.DoDragDrop(source, DragDropEffects.Move)

            Exit For
        End If
    Next
End Sub

Private Sub ListBox_DragEnter(ByVal sender As Object, _
                              ByVal e As DragEventArgs) Handles ListBox1.DragEnter, _
                                                                ListBox2.DragEnter
    Dim source As ListBox = DirectCast(sender, ListBox)

    If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) AndAlso _
       e.Data.GetData("System.Windows.Forms.ListBox", False) IsNot source Then
        'The data being dragged is a ListBox but not the one that was just entered.
        e.Effect = DragDropEffects.Move
    End If
End Sub

Private Sub ListBox_DragDrop(ByVal sender As Object, _
                             ByVal e As DragEventArgs) Handles ListBox1.DragDrop, _
                                                               ListBox2.DragDrop
    Dim source As ListBox = DirectCast(sender, ListBox)

    If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) Then
        'Get the ListBox that the data was dragged from.
        Dim data As ListBox = DirectCast(e.Data.GetData("System.Windows.Forms.ListBox", _
                                                        False),  _
                                         ListBox)

        'Make sure we aren't trying to drag from and drop to the same control.
        If data IsNot source Then
            'Get the item that was dragged.
            Dim item As Object = data.SelectedItem

            'Remove the item from its original location.
            data.Items.Remove(item)

            'Get the current mouse location relative to the control being dropped on.
            Dim location As Point = source.PointToClient(New Point(e.X, e.Y))
            Dim dropIndex As Integer = -1

            'Find the item over which the mouse was released.
            For index As Integer = 0 To source.Items.Count - 1
                If source.GetItemRectangle(index).Contains(location) Then
                    dropIndex = index

                    Exit For
                End If
            Next

            If dropIndex = -1 Then
                'The mouse was not released over an item so add the new item to the end.
                source.Items.Add(item)
            Else
                'Insert the new item above the item it was dropped on.
                source.Items.Insert(dropIndex, item)
            End If
        End If
    End If
End Sub
```

4. Run the project and start dragging and dropping.

I'll refine this example and add more over time.  If there's anything you specifically want to see then post a request and I'll see if I can get to it.

As requested in post #34, I have reworked the above example to allow multiple items to be dragged and dropped.
vb.net Code:
Private Sub Form1_Load(ByVal sender As Object, _                   ByVal e As EventArgs) Handles MyBase.Load    'Allow data to be dropped on both ListBoxes.    Me.ListBox1.AllowDrop = True    Me.ListBox2.AllowDrop = True     'All multiple selections.    Me.ListBox1.SelectionMode = SelectionMode.MultiExtended    Me.ListBox2.SelectionMode = SelectionMode.MultiExtended     'Populate the ListBoxes.    Me.ListBox1.Items.AddRange(New String() {"List 1, Item 1", _                                             "List 1, Item 2", _                                             "List 1, Item 3", _                                             "List 1, Item 4", _                                             "List 1, Item 5"})    Me.ListBox2.Items.AddRange(New String() {"List 2, Item 1", _                                             "List 2, Item 2", _                                             "List 2, Item 3", _                                             "List 2, Item 4", _                                             "List 2, Item 5"})End Sub Private Sub ListBox_MouseDown(ByVal sender As Object, _                              ByVal e As MouseEventArgs) Handles ListBox1.MouseDown, _                                                                 ListBox2.MouseDown    Dim source As ListBox = DirectCast(sender, ListBox)     For index As Integer = 0 To source.Items.Count - 1        'Test whether the mouse location is within an item        If source.GetItemRectangle(index).Contains(e.Location) Then            'The mouse was depressed on an item so allow a move operation.            source.DoDragDrop(source, DragDropEffects.Move)             Exit For        End If    NextEnd Sub Private Sub ListBox_DragEnter(ByVal sender As Object, _                              ByVal e As DragEventArgs) Handles ListBox1.DragEnter, _                                                                ListBox2.DragEnter    Dim source As ListBox = DirectCast(sender, ListBox)     If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) AndAlso _       e.Data.GetData("System.Windows.Forms.ListBox", False) IsNot source Then        'The data being dragged is a ListBox but not the one that was just entered.        e.Effect = DragDropEffects.Move    End IfEnd Sub Private Sub ListBox_DragDrop(ByVal sender As Object, _                             ByVal e As DragEventArgs) Handles ListBox1.DragDrop, _                                                               ListBox2.DragDrop    Dim source As ListBox = DirectCast(sender, ListBox)     If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) Then        'Get the ListBox that the data was dragged from.        Dim data As ListBox = DirectCast(e.Data.GetData("System.Windows.Forms.ListBox", _                                                        False),  _                                         ListBox)         'Make sure we aren't trying to drag from and drop to the same control.        If data IsNot source Then            'Get the items that were dragged.            Dim items As Object() = data.SelectedItems.Cast(Of Object).ToArray()             'Remove the items from their original location.            For Each item In items                data.Items.Remove(item)            Next             'Get the current mouse location relative to the control being dropped on.            Dim location As Point = source.PointToClient(New Point(e.X, e.Y))            Dim dropIndex As Integer = -1             'Find the item over which the mouse was released.            For index As Integer = 0 To source.Items.Count - 1                If source.GetItemRectangle(index).Contains(location) Then                    dropIndex = index                     Exit For                End If            Next             If dropIndex = -1 Then                'The mouse was not released over an item so add the new items to the end.                source.Items.AddRange(items)            Else                'Insert the new items above the item they were dropped on.                For Each item In items                    source.Items.Insert(dropIndex, item)                    dropIndex += 1                Next            End If        End If    End IfEnd Sub

----------


## jmcilhinney

This example demonstrates dragging one or more files from Windows Explorer, or some other application that supports dragging files, into a ListView.

1. Create a new WinForms project.
2. Add a ListView and an ImageList to the form.
3. Add the following code:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    'Initialise the ListView.
    Me.ListView1.AllowDrop = True
    Me.ListView1.Columns.Add("File name")
    Me.ListView1.Dock = DockStyle.Fill
    Me.ListView1.SmallImageList = Me.ImageList1
    Me.ListView1.View = View.Details
End Sub

Private Sub ListView1_DragEnter(ByVal sender As Object, _
                                ByVal e As DragEventArgs) Handles ListView1.DragEnter
    If e.Data.GetDataPresent("FileDrop") AndAlso _
       (e.AllowedEffect And DragDropEffects.Copy) = DragDropEffects.Copy Then
        'A file list is being dragged and it can be copied so provide feedback to the user.
        e.Effect = DragDropEffects.Copy
    End If
End Sub

Private Sub ListView1_DragDrop(ByVal sender As Object, _
                               ByVal e As DragEventArgs) Handles ListView1.DragDrop
    'The data can only be dropped if it is a file list and it can be copied.
    If e.Data.GetDataPresent("FileDrop") AndAlso _
       (e.AllowedEffect And DragDropEffects.Copy) = DragDropEffects.Copy Then
        'Get the data.
        Dim filePaths As String() = DirectCast(e.Data.GetData("FileDrop"), _
                                              String())

        Dim upperBound As Integer = filePaths.GetUpperBound(0)
        Dim items(upperBound) As ListViewItem
        Dim filePath As String

        'For each file in the list, create an item, complete with icon.
        For index As Integer = 0 To upperBound
            filePath = filePaths(index)

            If Not Me.ImageList1.Images.Keys.Contains(filePath) Then
                'This is the first time this file has been added so add its icon too.
                Me.ImageList1.Images.Add(filePath, _
                                         Icon.ExtractAssociatedIcon(filePath))
            End If

            items(index) = New ListViewItem(filePath, filePath)
        Next

        'Add the items to the ListView.
        Me.ListView1.Items.AddRange(items)
    End If
End Sub
```

4. Run the project.
5. Select one or more files in Windows Explorer and drag them onto your form.

Tada!  Note that, as before, I've done some setup of design time elements that you'd normally do in the designer.  It was easier to do it in code than to explain though, for the purpose of this example.

----------


## jmcilhinney

I'm going to use that last example as a basis for showing you how to build up drag & drop code.  I can hear people now saying "But how would I know to use the FileDrop format and how would I know that it returns a String array".  Well, I'm going to show you how you work that out.

First up, you have to make sure that your control is a drop target, so set its AllowDrop property to True.  Next you need to test what formats the data being dragged is available in.  To do that you use the GetFormats method.  GetFormats returns a String array, so you can loop through it to see what formats you can get the data in:
vb.net Code:
Private Sub ListView1_DragEnter(ByVal sender As Object, _                                ByVal e As DragEventArgs) Handles ListView1.DragEnter    For Each format As String In e.Data.GetFormats()        MessageBox.Show(format)    NextEnd Sub
Drag your data onto the control and it will start popping up messages for each format.  You might prefer to use Console.WriteLine and view the list in the Output window as it's less intrusive.

You now need to determine what .NET object will be created if you get the data in each of those formats and then decide which of those is most useful to you.  To do that, you first need to get the data in each of those formats and then test it's type:
vb.net Code:
Private Sub ListView1_DragEnter(ByVal sender As Object, _                                ByVal e As DragEventArgs) Handles ListView1.DragEnter    For Each format As String In e.Data.GetFormats()        MessageBox.Show(e.Data.GetData(format).GetType().ToString(), format)    NextEnd Sub
You can then examine each of those objects based on its .NET type.  Those that return a MemoryStream are going to be a little harder to interpret, but the String arrays are going to be easy to examine, so let's start with them:
vb.net Code:
Private Sub ListView1_DragEnter(ByVal sender As Object, _                                ByVal e As DragEventArgs) Handles ListView1.DragEnter    Dim strings As String()     For Each format As String In e.Data.GetFormats()        strings = TryCast(e.Data.GetData(format), String())         If strings IsNot Nothing Then            MessageBox.Show(String.Join(Environment.NewLine, _                                        strings), _                            format)        End If    NextEnd Sub
So, having done that by dragging multiple files you will now know that the FileName format returns the path of the first file in DOS-compatible format, the FileNameW format returns the full path of the first file and the FileDrop format returns the full paths of all the files.  In this case that's as far as we need to go because the full paths of all files is exactly what we need.  We now know that we need to test for the FileDrop format, which we do with GetDataPresent, and then get the data in that format, which we do with GetData.

That's basically how you should approach all drag & drop operations.

----------


## jmcilhinney

1. Create a new Windows Forms project.
2. Add a ListBox to the form.
3. Add the following code:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    'Initialise the ListBox.
    Me.ListBox1.AllowDrop = True
    Me.ListBox1.Items.AddRange(New String() {"Item 1", _
                                             "Item 2", _
                                             "Item 3", _
                                             "Item 4", _
                                             "Item 5"})
End Sub

Private Sub ListBox1_MouseDown(ByVal sender As Object, _
                               ByVal e As MouseEventArgs) Handles ListBox1.MouseDown
    'Test whether the mouse is over an item.
    If Me.GetItemIndexAtPoint(e.Location) <> -1 Then
        'The mouse is over an item so start dragging.
        Me.ListBox1.DoDragDrop(Me.ListBox1, DragDropEffects.Move)
    End If
End Sub

Private Sub ListBox1_DragEnter(ByVal sender As Object, _
                               ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox1.DragEnter, _
                                                                                      ListBox1.DragOver
    'Test whether the data being dragged is the ListBox itself.
    If e.Data.GetDataPresent("System.Windows.Forms.ListBox") AndAlso _
       e.Data.GetData("System.Windows.Forms.ListBox") Is Me.ListBox1 Then
        'Get the location of the mouse relative to the ListBox.
        Dim mouseLocation As Point = Me.ListBox1.PointToClient(New Point(e.X, e.Y))

        'Force the location to be within the horizontal bounds of the ListBox.
        If mouseLocation.X < 0 Then
            mouseLocation.X = 0
        ElseIf mouseLocation.X > Me.ListBox1.Width Then
            mouseLocation.X = Me.ListBox1.Width
        End If

        'Force the location to be within the vertical bounds of the ListBox.
        If mouseLocation.Y < 0 Then
            mouseLocation.Y = 0
        ElseIf mouseLocation.Y > Me.ListBox1.Height Then
            mouseLocation.Y = Me.ListBox1.Height
        End If

        If Me.GetItemIndexAtPoint(mouseLocation) = Me.ListBox1.SelectedIndex Then
            'Don't allow the selected item to be dropped on itself.
            e.Effect = DragDropEffects.None
        Else
            'Allow the selected item to be moved.
            e.Effect = DragDropEffects.Move
        End If
    End If
End Sub

Private Sub ListBox1_DragDrop(ByVal sender As Object, _
                              ByVal e As DragEventArgs) Handles ListBox1.DragDrop
    'Test whether the data being dragged is the ListBox itself and the selected item can be moved.
    If e.AllowedEffect = DragDropEffects.Move AndAlso _
       e.Data.GetDataPresent("System.Windows.Forms.ListBox") AndAlso _
       e.Data.GetData("System.Windows.Forms.ListBox") Is Me.ListBox1 Then
        Dim selectedIndex As Integer = Me.ListBox1.SelectedIndex

        'Get the index of the item being dropped on.
        Dim dropIndex As Integer = Me.GetItemIndexAtPoint(Me.ListBox1.PointToClient(New Point(e.X, e.Y)))

        'If the item being dropped on is below the selected item, the index of the
        'item being dropped on will decrement once the selected item is removed.
        If dropIndex > selectedIndex Then
            dropIndex -= 1
        End If

        Dim selectedItem As Object = Me.ListBox1.SelectedItem

        Me.ListBox1.Items.Remove(selectedItem)

        If dropIndex = -1 Then
            'The item was dropped after the last item so add it at the end of the list.
            Me.ListBox1.Items.Add(selectedItem)
        Else
            'Insert the item above the item it was dropped on.
            Me.ListBox1.Items.Insert(dropIndex, selectedItem)
        End If

        Me.ListBox1.SelectedItem = selectedItem
    End If
End Sub

Private Function GetItemIndexAtPoint(ByVal location As Point) As Integer
    Dim itemIndex As Integer = -1

    For index As Integer = 0 To Me.ListBox1.Items.Count - 1
        'Test whether the location is within an item.
        If Me.ListBox1.GetItemRectangle(index).Contains(location) Then
            itemIndex = index

            Exit For
        End If
    Next

    Return itemIndex
End Function
```

4. Run the project and start dragging.

When you drop an item it will be moved to the position above the item you dropped it on.  If you drop it after the last item it will be moved to the end of the list.

----------


## Xancholy

I request sample drag drop code for a picturebox. 
Also how to refuse multiple file drops and limit to single dropped file.

Thanks.

----------


## jmcilhinney

> I request sample drag drop code for a picturebox. 
> Also how to refuse multiple file drops and limit to single dropped file.
> 
> Thanks.


The first thing to note is that the AllowDrop property of the PictureBox class is not designer-visible.  I'm not sure why this is because the PictureBox does support drag & drop.  As a result you will have to set the property in code.

Now, this first code example will allow you to drop multiple files on the PictureBox but it simply ignores all but the first file:
vb.net Code:
Private Sub Form1_Load(ByVal sender As System.Object, _                       ByVal e As System.EventArgs) Handles MyBase.Load    'Let the PictureBox accept dropped data.    Me.PictureBox1.AllowDrop = TrueEnd Sub Private Sub PictureBox1_DragEnter(ByVal sender As Object, _                                  ByVal e As DragEventArgs) Handles PictureBox1.DragEnter    'Only allow copying and then only if one or more files are being dragged and the first one is an image file.    If (e.AllowedEffect And DragDropEffects.Copy) = DragDropEffects.Copy AndAlso _       e.Data.GetDataPresent("FileDrop", True) AndAlso _       Me.IsImageFile(DirectCast(e.Data.GetData("FileDrop", True), String())(0)) Then        e.Effect = DragDropEffects.Copy    End IfEnd Sub Private Sub PictureBox1_DragDrop(ByVal sender As Object, _                                 ByVal e As DragEventArgs) Handles PictureBox1.DragDrop    If e.Effect = DragDropEffects.Copy Then        'Load the first file.        Me.PictureBox1.Load(DirectCast(e.Data.GetData("FileDrop", True), String())(0))    End IfEnd Sub ''' <summary>''' Determines whether the specified path contains an image file.''' </summary>''' <param name="path">''' The path of the file to test.''' </param>''' <returns>''' <b>True</b> if <i>path</i> contains an image file; otherwise, <b>False</b>.''' </returns>Private Function IsImageFile(ByVal path As String) As Boolean    Dim result As Boolean     Try        'Try to create an image from the file.        Using img As Image = Image.FromFile(path)        End Using         'The operation succeeded so the file must contain an image.        result = True    Catch ex As Exception        'The path does not contain a valid image file.        result = False    End Try     Return resultEnd Function
Analysing this code, in the DragEnter event handler we test whether it is files that are being dragged and that the first one is an image.  If that's the case then a copy cursor is displayed.  Even if there are other files that are not images they are simply ignored.

In the DragDrop event handler we don't need to test the data again because we know that, if the effect is Copy then the data must have passed the test in the DragEnter event handler.  That means we simply get the first file path and load it into the PictureBox.

It should be noted that the IsImageFile method is using a brute force approach to determine whether the file is an image or not.  It simply creates an Image object and handles the exception that's thrown if it fails.  This is not ideal but there really isn't another way (that I'm aware of) to perform this test.

For clarity, here's the DragEnter event handler rewritten with the code extended out a bit:
vb.net Code:
Private Sub PictureBox1_DragEnter(ByVal sender As Object, _                                  ByVal e As DragEventArgs) Handles PictureBox1.DragEnter    'Only allow copying and then only if one or more files are being dragged and the first one is an image file.    If (e.AllowedEffect And DragDropEffects.Copy) = DragDropEffects.Copy AndAlso _       e.Data.GetDataPresent("FileDrop", True) Then        Dim data As Object = e.Data.GetData("FileDrop", True)        Dim filePaths As String() = DirectCast(data, String())        Dim firstFilePath As String = filePaths(0)         If Me.IsImageFile(firstFilePath) Then            e.Effect = DragDropEffects.Copy        End If    End IfEnd Sub
If you want to prevent multiple files being dropped at all then you can do this:
vb.net Code:
Private Sub PictureBox1_DragEnter(ByVal sender As Object, _                                  ByVal e As DragEventArgs) Handles PictureBox1.DragEnter    'Only allow copying and then only if one file is being dragged and it is an image file.    If (e.AllowedEffect And DragDropEffects.Copy) = DragDropEffects.Copy AndAlso _       e.Data.GetDataPresent("FileDrop", True) Then        Dim data As Object = e.Data.GetData("FileDrop", True)        Dim filePaths As String() = DirectCast(data, String())         If filePaths.Length = 1 Then            Dim firstFilePath As String = filePaths(0)             If Me.IsImageFile(firstFilePath) Then                e.Effect = DragDropEffects.Copy            End If        End If    End IfEnd Sub

----------


## Xancholy

Thank you for this comprehensive post. 

Also one could use your 'save image in database' code to save the dropped file path to a database.

If users can add the image of the file being dropped as custom cursor that would be a complete solution.

----------


## jmcilhinney

> Also one could use your 'save image in database' code to save the dropped file path to a database.


My last post shows you how to get an Image object from a dropped file and that other thread shows you how to save an Image object to a database.  Putting the two together should be a piece of cake and is not something I'll be providing code for explicitly.


> If users can add the image of the file being dropped as custom cursor that would be a complete solution.


I've bookmarked that Code Project article you found and I might look at creating an example that references that C++ code some time in the future.

----------


## Xancholy

Can you show us best practice for bound/unbound datagridview cell/row drag drop :
Reorder within same datagridview (how does one reorder a bound DGV ?)Drag drop copy to unbound datagriview

Is it possible to show dgv cell contents as the cursor during drag drop ?

Thanks

----------


## Xancholy

> I've bookmarked that Code Project article you found and I might look at creating an example that references that C++ code some time in the future.


That would be a great help. Thanks.

----------


## Xancholy

> Can you show us best practice for bound/unbound datagridview cell/row drag drop :
> Reorder within same datagridview (how does one reorder a bound DGV ?)Drag drop copy to unbound datagriview
> 
> Is it possible to show dgv cell contents as the cursor during drag drop ?
> 
> Thanks


jmc, I was wondering if you had some time to show us what the best way to drag and drop in datagridviews ?

----------


## theopres

hey it's me again...great. i didn't see that you had this thread in vb too...
can i ask if it's possible to make the program Reordering Items in a ListBox using a combobox?i can see that GetItemRectangle is not a member of System.Windows.Forms.ComboBox but is it possible to be done or should i stop trying???
thanks for the help...

----------


## pidyok

question please... how do you perform Drag Drop between 2 datagrids BETWEEN 2 different MDI child forms... had a tough time for this one... my apologies... Thanks...

----------


## jmcilhinney

> hey it's me again...great. i didn't see that you had this thread in vb too...
> can i ask if it's possible to make the program Reordering Items in a ListBox using a combobox?i can see that GetItemRectangle is not a member of System.Windows.Forms.ComboBox but is it possible to be done or should i stop trying???
> thanks for the help...


I think you can pretty much forget that one.  That would be unintuitive UI design anyway.

----------


## jmcilhinney

> question please... how do you perform Drag Drop between 2 datagrids BETWEEN 2 different MDI child forms... had a tough time for this one... my apologies... Thanks...


Do you mean DataGrid or DataGridView.  How are the grids populated in the first place?

----------


## Xancholy

> jmc, I was wondering if you had some time to show us what the best way to drag and drop in datagridviews ?


jmc, do you have a moment to help with this one ?

----------


## melvin74

Is there a way to limit the file type extension?  I want to just allow dragging of .pdf files into my listbox.

----------


## jmcilhinney

> Is there a way to limit the file type extension?  I want to just allow dragging of .pdf files into my listbox.


In the DragEnter event handler you would get the file path and only allow the operation to continue if it had a ".pdf" extension.  You'll see in my DragEnter event handlers if have If statements that restrict continuation of the operation to certain conditions.  In post #6 that includes getting the file path and passing it to my IsImageFile method.  You would get the file path the same way, get its extension using Path.GetExtension and then compare that to ".pdf".

----------


## ForumAccount

Hey jmc, nice code, I just wanted to bring a couple things to your attention. 

Instead of:



```
e.Data.GetDataPresent("FileDrop", True)
```

wouldn't it be more proper to do:



```
e.Data.GetDataPresent(DataFormats.FileDrop, True)
```

Also:



```
Icon.ExtractAssociatedIcon(File)
```

should result in a warning and really should be:



```
Drawing.Icon.ExtractAssociatedIcon(File)
```

For your Drag & Drop method in post #2 you could shorten some of the code:


vb.net Code:
Private Sub lvMain_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles lvMain.DragDrop        If e.Data.GetDataPresent(DataFormats.FileDrop, False) Then            Dim Files() As String = DirectCast(e.Data.GetData(DataFormats.FileDrop, False), String())            For Each File As String In Files                If Not Me.ilListView.Images.Keys.Contains(File) Then                    Me.ilListView.Images.Add(File, Drawing.Icon.ExtractAssociatedIcon(File))                End If                With Me.lvMain.Items.Add(IO.Path.GetFileName(File))                    .ImageIndex = ilListView.Images.IndexOfKey(File)                End With            Next        End IfEnd Sub

Anyway, I always come back to this code because I always forget certain drag & drop things, so thanks for the code!

----------


## jmcilhinney

> Hey jmc, nice code, I just wanted to bring a couple things to your attention. 
> 
> Instead of:
> 
> 
> 
> ```
> e.Data.GetDataPresent("FileDrop", True)
> ```
> ...


The first point is quite valid.  The second point is also quite valid but, interestingly, I just pasted my code into VS 2008 and there was no warning about ExtractAssociatedIcon being a Shared method, even though Icon was identified as being the Icon property of the form and not the Icon class.  I guess that's why I missed it.

With regards to the third point, yes your code is shorter but not necessarily better.  If you're going to be adding multiple items to a ListView or other control, or in fact any collection, then the preferred way is to put those items into an array first and then call AddRange rather than calling Add once for each item.  This is mainly to avoid lots of events being raised when adding multiple items.  It's especially important with controls because each time you add an item the control will be redrawn.  If you add 100 items you don't want the control redrawn 100 times, so you call AddRange and it gets redrawn once only.

Anyway, thanks for the contribution.

----------


## pidyok

how do you perform Drag & Drop of a row between 2 datagrids BETWEEN 2 MDI child forms populated either manually or from a recordset initially... i have a common child form with a datagrid which is "like" being duplicated everytime i launch a child form... i progress through programming by referring mostly on examples... but for this issue, i've scoured the net but to no avail.. to date, its been 5 months since my last post and still no luck... hoping for somebody to help me on this topic...

thank you...

cheers!!!

----------


## jmcilhinney

Here's an example of using drag and drop to move a row in a DataGridView.  I'll extend this example in future posts.

----------


## jmcilhinney

Here's another example using the DataGridView that answers the question of dragging between MDI child forms asked earlier.  Sorry to make you wait so long.

----------


## pidyok

i'll consider your example... nice to know different approaches... thnks jmcilhinney... rep added...

cheers...

----------


## DragonRose

Hi jmcilhinney, im having a issue with dragging between 2 listboxes, using your firstcode sample, i have 2 listboxes (listbox 2, and listbox4) and i changed the code to suit the name, but its not working theres no error etc, but the item that i drag from listbox 2 does not spear in listbox 4.

Heres the code i have:



```
    Private Sub ListBox_MouseDown(ByVal sender As Object, _
                              ByVal e As MouseEventArgs) Handles ListBox2.MouseDown, _
                                                                 ListBox4.MouseDown
        Dim source As ListBox = DirectCast(sender, ListBox)

        For index As Integer = 0 To source.Items.Count - 1
            'Test whether the mouse location is within an item
            If source.GetItemRectangle(index).Contains(e.Location) Then
                'The mouse was depressed on an item so allow a move operation.
                source.DoDragDrop(source, DragDropEffects.Move)

                Exit For
            End If
        Next
    End Sub
    Private Sub ListBox_DragEnter(ByVal sender As Object, _
                                  ByVal e As DragEventArgs) Handles ListBox2.DragEnter, _
                                                                    ListBox4.DragEnter
        Dim source As ListBox = DirectCast(sender, ListBox)

        If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) AndAlso _
           e.Data.GetData("System.Windows.Forms.ListBox", False) IsNot source Then
            'The data being dragged is a ListBox but not the one that was just entered.
            e.Effect = DragDropEffects.Move
        End If
    End Sub
    Private Sub ListBox_DragDrop(ByVal sender As Object, _
                                 ByVal e As DragEventArgs) Handles ListBox2.DragDrop, _
                                                                   ListBox4.DragDrop
        Dim source As ListBox = DirectCast(sender, ListBox)

        If e.Data.GetDataPresent("System.Windows.Forms.ListBox", False) Then
            'Get the ListBox that the data was dragged from.
            Dim data As ListBox = DirectCast(e.Data.GetData("System.Windows.Forms.ListBox", _
                                                            False),  _
                                             ListBox)

            'Make sure we aren't trying to drag from and drop to the same control.
            If data IsNot source Then
                'Get the item that was dragged.
                Dim item As Object = data.SelectedItem

                'Remove the item from its original location.
                data.Items.Remove(item)

                'Get the current mouse location relative to the control being dropped on.
                Dim location As Point = source.PointToClient(New Point(e.X, e.Y))
                Dim dropIndex As Integer = -1

                'Find the item over which the mouse was released.
                For index As Integer = 0 To source.Items.Count - 1
                    If source.GetItemRectangle(index).Contains(location) Then
                        dropIndex = index

                        Exit For
                    End If
                Next

                If dropIndex = -1 Then
                    'The mouse was not released over an item so add the new item to the end.
                    source.Items.Add(item)
                Else
                    'Insert the new item above the item it was dropped on.
                    source.Items.Insert(dropIndex, item)
                End If
            End If
        End If
    End Sub
```

Can you see anything im doing wrong? Thanks.

----------


## jmcilhinney

> Can you see anything im doing wrong? Thanks.


There's nothing at all wrong with that code.  It works perfectly, exactly as it should.  What's different about your code compared to mine?  You don't have my Load event handler.  Is there anything in my Load event handler that might be important?  Also, in my first post I provided two links to information that you should read if you're interested in drag & drop.  The second of those two links covers why you're having an issue.  You presumably didn't read that information.  If you simply copy and paste code then you are quite likely to not understand it properly, which is why I provided those links.

----------


## DragonRose

The only code from the load event im missing is this:



```
    'Populate the ListBoxes.
    Me.ListBox1.Items.AddRange(New String() {"List 1, Item 1", _
                                             "List 1, Item 2", _
                                             "List 1, Item 3", _
                                             "List 1, Item 4", _
                                             "List 1, Item 5"})
    Me.ListBox2.Items.AddRange(New String() {"List 2, Item 1", _
                                             "List 2, Item 2", _
                                             "List 2, Item 3", _
                                             "List 2, Item 4", _
                                             "List 2, Item 5"})
```

The allow drop code i have, but the above code is just to populate the lists, since my lists are already populated it is not needed. I have the links bookmarked to read today since i was just on my way to bed after posting last night, so ill read those now.

----------


## jmcilhinney

> The allow drop code i have


I copied and pasted your code into a new project and it worked perfectly.  The only thing extra that I had to do was set the AllowDrop properties of the two ListBoxes to True.  If that code is not working for you then the only reason I can see would be that you haven't done that.

----------


## DragonRose

Strange, because besides having the allow drop set via the load event i also tried setting it int he listbox properties to see if that made any difference but it never.

When i click/drag from listbox2 the symbol to show that im dragging appears, but when dropped on listbox 4 it doesn't show up, would how the list box is populated matter? Because mine is populated from a dirInfoArray.

----------


## jmcilhinney

As long as the items are added directly to the ListBox and not bound then there's no reason it shouldn't work.  If the data is bound then you would have to work with the items in the data source(s) and not in the control(s), which is always the case with bound data.

----------


## Shaggy Hiker

I saved a link to this because I thought I would use it some day, and now I was able to do so. Actually, that's probably not the case, since I've done lots of drag and drop, it's just that JMC wrote one specific example that I had never done myself, but which I was doing for this project.

My one question, in case this thread is still occasionally observed, is why there is the GetItemIndexAtPoint method when there is the IndexFromPoint method for the listbox already. I don't see any advantage to the custom method over the built-in method.

----------


## jmcilhinney

> My one question, in case this thread is still occasionally observed, is why there is the GetItemIndexAtPoint method when there is the IndexFromPoint method for the listbox already. I don't see any advantage to the custom method over the built-in method.


I can only assume that I didn't notice that existing method at the time.

----------


## Miklogak

I saw this Topic from outside, and I had to login just to Thanks @jmcilhinney for the Hardwork and amazing Job. This topic has now become my favorit Topic on vBForums. I did not expect finding such a usefull topic when I first saw the Title.

Thanks jmcilhinney, Your hard work has definitely paid off brother!

+Rep

----------


## Signalman

This is a really good thread.  In the example in post 1, you could you possibly modify it so that you can copy more than one item at a time ?

----------


## jmcilhinney

> This is a really good thread.  In the example in post 1, you could you possibly modify it so that you can copy more than one item at a time ?


I have added the requested example to post #1. Enjoy.  :Smilie:

----------


## Signalman

I have been playing around with the amended example, which does indeed drag and drop multiple items.  One thing that is a little confusing is that it works in a different way to windows normally.  

If in windows explorer, you select multiple items,by clicking the first one, then pressing  shift clicking (and releasing) on the last item, the selection is complete.  If you then click & Hold on any of the items selected, you can then drag all the selected items.

If however you repeat the process with the example code, when you click and hold any of the previously selected items, they are all de selected apart from the one you have clicked on.

is it possible to make it work the same as in Windows Explorer ?

----------


## jmcilhinney

> is it possible to make it work the same as in Windows Explorer ?


I would imagine so.  What have you tried?

----------


## Signalman

I have stepped thro the different sections of the code and from what I can see the selection & highlighting of the individual selected items are part of the core windows code and not part of the code that I can amend.  It is only the actual drag and drop that is coded.  There of course be some control that I am not aware of.

I may of course be totally wrong :-)

----------

