Need to have your ListView scroll while using Drag and Drop? This article shows the code. It's not complex, but the documentation is hard to locate in .NET. I actually looked, off and on for several days, in Google and MSDN, and never found any .NET code for making the ListView scroll.
Finally, by trial and error, I got the ListView to scroll with Drag and Drop. I was able to find some VB6 and some C# code, but was never able to make any of it work. When you actually see the code, there is not much to it.
I must give credit to Bruce Gordon for providing an upgrade to this code and making the scrolling run much smoother. Therefore, because of his great tip and rewritten DragOver event, I am republishing this article with the code that he sent me. THANKS BRUCE!
This article will give you the code for both Drag and Drop and automatic scrolling of the ListView. I use it to reorder ListViewItems in the ListView. First, place a ListView on a Windows Form. I set the MultiSelect Property to True so that the user can select and drag multiple items. If you name the ListView "lvCodeElts", you can plug the code and it should work with no problems. Otherwise, just replace all instances of "lvCodeElts" with the name of your ListView. Also add a Timer control to the form. Figure 1 shows the code for beginning the Drag and Drop.
Figure 1 - Begin Drag and Drop.
| Private Sub lvCodeElts_ItemDrag(ByVal sender As Object, _ ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles lvCodeElts.ItemDrag 'Begins a drag-and-drop operation in the ListView control. lvCodeElts.DoDragDrop(lvCodeElts.SelectedItems, DragDropEffects.Move) End Sub |
| Private Sub lvCodeElts_DragEnter(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) Handles lvCodeElts.DragEnter Dim i As Integer For i = 0 To e.Data.GetFormats().Length - 1 If e.Data.GetFormats()(i).Equals _ ("System.Windows.Forms.ListView+SelectedListViewItemCollection") Then 'The data from the drag source is moved to the target. e.Effect = DragDropEffects.Move End If Next End Sub |
| ''' <summary> ''' Allow reordering of items within a ListView. Moves all selected ''' items to a point before the item on which the dragged item(s) are dropped. ''' Exit if the items are not selected in the ListView control. ''' While moving up, the dragged items are inserted above the item on which ''' they are dropped. On dragging down, the dragged items are inserted below ''' the item on which they are dropped. This is by design, otherwise you could ''' not insert both above and below the first and last item. ''' </summary> ''' <param name="sender" ></param> ''' <param name="e" ></param> ''' <remarks></remarks> Private Sub lvCodeElts_DragDrop(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) Handles lvCodeElts.DragDrop If lvCodeElts.SelectedItems.Count = 0 Then Exit Sub 'Returns the location of the mouse pointer in the ListView control. Dim p As Point = lvCodeElts.PointToClient(New Point(e.X, e.Y)) 'Obtain the item that is located at the specified location of the mouse pointer. ' dragItem is the lvi upon which the drop is made Dim dragToItem As ListViewItem = lvCodeElts.GetItemAt(p.X, p.Y) If dragToItem Is Nothing Then Exit Sub 'Obtain the index of the item at the mouse pointer. ' dragIndes is the index of the lvi on which the items are dropped Dim dragIndex As Integer = dragToItem.Index Dim i As Integer ' create an array large enough to hold the selected (dragged) items Dim sel(lvCodeElts.SelectedItems.Count) As ListViewItem ' the following code moves the dragged selection to their new location. For i = 0 To lvCodeElts.SelectedItems.Count - 1 sel(i) = lvCodeElts.SelectedItems.Item(i) Next For i = 0 To lvCodeElts.SelectedItems.Count - 1 'Obtain the ListViewItem to be dragged to the target location. Dim dragItem As ListViewItem = sel(i) Dim itemIndex As Integer = dragIndex If itemIndex = dragItem.Index Then Exit Sub If dragItem.Index < itemIndex Then itemIndex = itemIndex + 1 Else itemIndex = dragIndex + i End If 'Insert the item in the specified location. Dim insertItem As ListViewItem = CType(dragItem.Clone, ListViewItem) lvCodeElts.Items.Insert(itemIndex, insertItem) 'Removes the item from the initial location while 'the item is moved to the new location. lvCodeElts.Items.Remove(dragItem) Next End Sub |
| Private Sub ListView1_DragOver(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) Handles ListView1.DragOver Dim position As Point position = New Point(0, 0) position.X = e.X position.Y = e.Y position = ListView1.PointToClient(position) mobjHoverItem = ListView1.GetItemAt(position.X, position.Y) If position.Y <= ListView1.Font.Height \ 2 Then ' getting close to top, ensure previous item is visible mintScrollDirection = 0 tmrLVScroll.Enabled = True ElseIf position.Y >= ListView1.ClientSize.Height - ListView1.Font.Height \ 2 Then ' getting close to bottom, ensure next item is visible mintScrollDirection = 1 tmrLVScroll.Enabled = True Else tmrLVScroll.Enabled = False End If e.Effect = DragDropEffects.Move position.X = e.X position.Y = e.Y position = ListView1.PointToClient(position) mobjHoverItem = ListView1.GetItemAt(position.X, position.Y) If IsNothing(mobjHoverItem) Then Exit Sub If mintSavedHoverIndex = mobjHoverItem.Index Then Exit Sub ListView1.BeginUpdate() ClearLVHighlight(ListView1) mobjHoverItem.BackColor = Color.DarkBlue mobjHoverItem.ForeColor = Color.White ListView1.EndUpdate() mintSavedHoverIndex = mobjHoverItem.Index End Sub |
| Private Sub ListView1_ItemDrag(ByVal sender As Object, _ ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles ListView1.ItemDrag 'Begins a drag-and-drop operation in the ListView control. ListView1.DoDragDrop(ListView1.SelectedItems, DragDropEffects.Move) End Sub |
| Private mintScrollDirection As Integer Private mobjHoverItem As ListViewItem Private mintSavedHoverIndex As Integer Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Integer, _ ByVal wMsg As Integer, _ ByVal wParam As Integer, _ ByRef lParam As Object) As Integer Private Sub tmrLVScroll_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles tmrLVScroll.Tick ScrollControl(ListView1, mintScrollDirection) End Sub Private Sub ScrollControl(ByRef objControl As Control, ByRef intDirection As Integer) ' This function enables a control (e.g. TreeView or ListView) to scroll ' during a drag-and-drop operation. ' For lngDirection, a value of 0 scrolls up; a value of 1 scrolls down. Const WM_SCROLL As Integer = &H115S SendMessage(objControl.Handle.ToInt32, WM_SCROLL, intDirection, VariantType.Null) End Sub Private Sub ClearLVHighlight(ByVal objLV As ListView) For intX As Integer = 0 To objLV.Items.Count - 1 objLV.Items(intX).ForeColor = Color.Black objLV.Items(intX).BackColor = Color.White Next End Sub |
| Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog. | ![]() |