elroyskimms
Member
- Joined
- Jul 10, 2015
- Messages
- 19
- Programming Experience
- 10+
You'll find sample code to illustrate the problem below. Make a new Form in a VS 2013 WinForm Project, paste and run.
I have 2 ListView controls and I have Drag & Drop working between the controls. Items can be moved from one control to the other. Items can be rearranged within the control as well.
When I enable Groups within the ListView controls (change .ShowGroups = False to .ShowGroups = True), everything continues to work... mostly. When I Drag an Item and Drop it directly onto another Item, everything works as intended and the items are re-arranged properly. However, when I Drag an Item and Drop it on the Group Header of another Item, the Dragged item is being moved to the end of the List (as if it were dropped at the end of the list intentionally). If you do a ListView.HitTest you will see that there is no difference in the ListViewHitTestInfo if you Drop on a Group Header or if you Drop at the end of the list. I need to be able to differentiate between a Drop on a Group Header and a Drop at the end of the ListView.
When I drop on the Header, I want to treat it like a Drop on an Item, and rearrange the Items accordingly. I can't assume that the user will never drop an Item on the Header row. Is there any way to identify the Drop point as being a Group Header?
-E
Code:
I have 2 ListView controls and I have Drag & Drop working between the controls. Items can be moved from one control to the other. Items can be rearranged within the control as well.
When I enable Groups within the ListView controls (change .ShowGroups = False to .ShowGroups = True), everything continues to work... mostly. When I Drag an Item and Drop it directly onto another Item, everything works as intended and the items are re-arranged properly. However, when I Drag an Item and Drop it on the Group Header of another Item, the Dragged item is being moved to the end of the List (as if it were dropped at the end of the list intentionally). If you do a ListView.HitTest you will see that there is no difference in the ListViewHitTestInfo if you Drop on a Group Header or if you Drop at the end of the list. I need to be able to differentiate between a Drop on a Group Header and a Drop at the end of the ListView.
When I drop on the Header, I want to treat it like a Drop on an Item, and rearrange the Items accordingly. I can't assume that the user will never drop an Item on the Header row. Is there any way to identify the Drop point as being a Group Header?
-E
Code:
VB.NET:
Public Class Form1
'Drag/Drop code taken from [URL]https://www.daniweb.com/software-development/vbnet/threads/342742/drag-and-drop-with-two-listviews[/URL]-
'Modified by me for Group support and reordering of ListViewItems
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'Adds to listview items to the form
Me.Size = New Size(400, 400)
Me.Controls.Clear()
Dim Listview1 As New ListView
Dim Listview2 As New ListView
Listview1.Location = New Point(50, 50)
Listview1.Name = "ListView1"
Listview2.Location = New Point(200, 50)
Listview2.Name = "ListView2"
Me.Controls.Add(Listview1)
Me.Controls.Add(Listview2)
For Each c As Control In Me.Controls
If TypeOf c Is ListView Then
With CType(c, ListView)
.AllowDrop = True
.Columns.Add("Name")
.Columns.Add("Type")
.FullRowSelect = True
.MultiSelect = False
.Size = New Size(150, 300)
.View = View.Details
.ShowGroups = False
AddHandler .ItemDrag, AddressOf ListView_ItemDrag
AddHandler .DragEnter, AddressOf ListView_DragEnter
AddHandler .DragDrop, AddressOf ListView_DragDrop
For i As Integer = 1 To 5
Dim lvItem As New ListViewItem(New String() {c.Name, i})
Dim grp As New ListViewGroup(c.Name & ":" & i, HorizontalAlignment.Center)
grp.Items.Add(lvItem)
.Items.Add(lvItem)
.Groups.Add(grp)
Next
End With
End If
Next
End Sub
Private Sub ListView_ItemDrag(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemDragEventArgs)
If sender Is Nothing OrElse Not TypeOf sender Is ListView Then Exit Sub
With CType(sender, ListView)
.DoDragDrop(e.Item, DragDropEffects.Move)
End With
End Sub
Private Sub ListView_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs)
If sender Is Nothing OrElse Not TypeOf sender Is ListView Then Exit Sub
'If this is a listview item then allow the drag
If e.Data.GetDataPresent(GetType(ListViewItem)) Then
e.Effect = DragDropEffects.Move
End If
End Sub
Private Sub ListView_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs)
If sender Is Nothing OrElse Not TypeOf sender Is ListView Then Exit Sub
'Remove the item from the current listview and drop it in the new listview
With CType(sender, ListView)
If e.Data.GetDataPresent(GetType(ListViewItem)) Then
Dim draggedItem As ListViewItem = CType(e.Data.GetData(GetType(ListViewItem)), ListViewItem)
'If this is the last Item in the group, remove the group from this list view or else you leave behind empty groups
If draggedItem.Group.Items.Count = 1 Then .Groups.Remove(draggedItem.Group)
draggedItem.ListView.Items.Remove(draggedItem)
Dim DropPoint As Point = .PointToClient(New Point(e.X, e.Y))
Dim ExistingItem As ListViewItem = .GetItemAt(DropPoint.X, DropPoint.Y)
Dim itemIndex As Integer = .Items.IndexOf(ExistingItem)
Dim groupIndex As Integer = -1
If Not ExistingItem Is Nothing Then groupIndex = .Groups.IndexOf(ExistingItem.Group)
'If there was no item in that spot, add this to the end of the list
If itemIndex < 0 Then
itemIndex = .Items.Count
End If
If groupIndex < 0 Then
groupIndex = .Groups.Count
End If
Dim grp As New ListViewGroup(draggedItem.Text & ":" & draggedItem.SubItems(1).Text, HorizontalAlignment.Center)
grp.Items.Add(draggedItem)
If groupIndex >= .Groups.Count Then
.Groups.Add(draggedItem.Group)
Else
.Groups.Insert(groupIndex + 1, draggedItem.Group)
End If
.Items.Insert(itemIndex, draggedItem)
End If
End With
End Sub
End Class