-
Drag & Drop in Windows Forms
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:
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
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 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 If
End Sub
-
Dragging Files From Windows Explorer
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:
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.
-
Determining How to Retrieve the Data
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)
Next
End 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)
Next
End 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
Next
End 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.
-
Reordering Items in a ListBox
1. Create a new Windows Forms project.
2. Add a ListBox to the form.
3. Add the following code:
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.
-
Re: Drag & Drop in Windows Forms
I request sample drag drop code for a picturebox.
Also how to refuse multiple file drops and limit to single dropped file.
Thanks.
-
Dropping Image Files on a PictureBox
Quote:
Originally Posted by Xancholy
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 = True
End 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 If
End 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 If
End 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 result
End 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 If
End 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 If
End Sub
-
Re: Drag & Drop in Windows Forms
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.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by Xancholy
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.
Quote:
Originally Posted by Xancholy
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.
-
Re: Drag & Drop in Windows Forms
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
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by jmcilhinney
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.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by 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 ?
-
Re: Drag & Drop in Windows Forms
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...
-
Re: Drag & Drop in Windows Forms
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...
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by 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...
I think you can pretty much forget that one. That would be unintuitive UI design anyway.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by 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...
Do you mean DataGrid or DataGridView. How are the grids populated in the first place?
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
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 ?
-
Re: Drag & Drop in Windows Forms
Is there a way to limit the file type extension? I want to just allow dragging of .pdf files into my listbox.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
melvin74
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".
-
Re: Drag & Drop in Windows Forms
Hey jmc, nice code, I just wanted to bring a couple things to your attention.
Instead of:
Code:
e.Data.GetDataPresent("FileDrop", True)
wouldn't it be more proper to do:
Code:
e.Data.GetDataPresent(DataFormats.FileDrop, True)
Also:
Code:
Icon.ExtractAssociatedIcon(File)
should result in a warning and really should be:
Code:
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 If
End Sub
Anyway, I always come back to this code because I always forget certain drag & drop things, so thanks for the code!
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
ForumAccount
Hey jmc, nice code, I just wanted to bring a couple things to your attention.
Instead of:
Code:
e.Data.GetDataPresent("FileDrop", True)
wouldn't it be more proper to do:
Code:
e.Data.GetDataPresent(DataFormats.FileDrop, True)
Also:
Code:
Icon.ExtractAssociatedIcon(File)
should result in a warning and really should be:
Code:
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 If
End Sub
Anyway, I always come back to this code because I always forget certain drag & drop things, so thanks for the code!
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.
-
Re: Drag & Drop in Windows Forms
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!!!
-
1 Attachment(s)
Re: Drag & Drop in Windows Forms
Here's an example of using drag and drop to move a row in a DataGridView. I'll extend this example in future posts.
-
1 Attachment(s)
Re: Drag & Drop in Windows Forms
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.
-
Re: Drag & Drop in Windows Forms
i'll consider your example... nice to know different approaches... thnks jmcilhinney... rep added...
cheers...
-
Re: Drag & Drop in Windows Forms
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:
Code:
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.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
DragonRose
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.
-
Re: Drag & Drop in Windows Forms
The only code from the load event im missing is this:
Code:
'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.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
DragonRose
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.
-
Re: Drag & Drop in Windows Forms
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.
-
Re: Drag & Drop in Windows Forms
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.
-
Re: Drag & Drop in Windows Forms
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.
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
Shaggy Hiker
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.
-
Re: Drag & Drop in Windows Forms
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
-
Re: Drag & Drop in Windows Forms
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 ?
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
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 ?
I have added the requested example to post #1. Enjoy. :)
-
Re: Drag & Drop in Windows Forms
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 ?
-
Re: Drag & Drop in Windows Forms
Quote:
Originally Posted by
Signalman
is it possible to make it work the same as in Windows Explorer ?
I would imagine so. What have you tried?
-
Re: Drag & Drop in Windows Forms
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 :-)