Auf der Suche nach einer Möglichkeit unter VB.NET ein Drag&Drop der Items im ListView-Control zu bewerkstelligen fand ich im Internet keine zufriedenstellende Lösung. Ein paar in C# programmierte DLLs sind verfügbar, keine hatte jedoch alle Funktionalitäten die ich gerne haben wollte. Außerdem funktionieren sie nicht richtig wenn das ListView im LargeIcon oder SmallIcon View läuft. Ein paar der Ideen aufgreifend möchte ich hier eine reine VB.NET Lösung vorstellen, die durch einen kleinen Trick auch für die Views LargeIcon und SmallIcon eine richtige Funktionsweise sicherstellt. Starten Sie zunächst ein neues Projekt und fügen Sie folgenden Code in ein neues Modul ein: Module Module1 Private scrollDirection As Integer Private LVhoverItem As ListViewItem Private savedLVHoverIndex As Integer Private WithEvents tmrLVScroll As New Windows.Forms.Timer Private LVtmrParam As ListView Private SelIndex As Integer ' benötigte API-Deklaration 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 Public Sub LV_DragDrop(ByVal lv As ListView, _ ByVal e As System.Windows.Forms.DragEventArgs) If lv.SelectedItems.Count = 0 Then Exit Sub Dim p As Point = lv.PointToClient(New Point(e.X, e.Y)) Dim dtItem As ListViewItem = lv.GetItemAt(p.X, p.Y) If dtItem Is Nothing Then Exit Sub Dim lvViewState As View = Nothing Dim dIndex As Integer = dtItem.Index Dim i As Integer Dim sel(lv.SelectedItems.Count) As ListViewItem For i = 0 To lv.SelectedItems.Count - 1 sel(i) = lv.SelectedItems.Item(i) Next For i = 0 To lv.SelectedItems.Count - 1 Dim dItem As ListViewItem = sel(i) Dim iIndex As Integer = dIndex If iIndex = dItem.Index Then lv.Invalidate() Exit Sub End If If dItem.Index < iIndex Then iIndex = iIndex + 1 Else iIndex = dIndex + i End If Dim insertitem As ListViewItem = dItem.Clone ' Nötig, um das Item auch bei Icon-Ansicht an die ' richtige Position zu bekommen: If lv.View = View.LargeIcon Or lv.View = View.SmallIcon Then lvViewState = lv.View lv.Visible = False lv.View = View.List lv.Items.Insert(iIndex, insertitem) lv.View = lvViewState lv.Visible = True Else lv.Items.Insert(iIndex, insertitem) End If lv.Items.Remove(dItem) ' Item an alter Position löschen lv.EnsureVisible(dIndex) ' Sichtbarkeit des neuen Items sicherstellen lv.Focus() Next End Sub Public Sub LV_DragEnter(ByVal e As System.Windows.Forms.DragEventArgs) 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 ' Gedragte Items ans Ziel bewegen e.Effect = DragDropEffects.Move End If Next End Sub Public Sub LV_DragOver(ByVal lv As ListView, _ ByVal e As System.Windows.Forms.DragEventArgs) Dim pos As Point pos = New Point(0, 0) ' Bestimmt wie flüssig und schnell der auto-scroll ist tmrLVScroll.Interval = 100 pos.X = e.X pos.Y = e.Y pos = lv.PointToClient(pos) LVhoverItem = lv.GetItemAt(pos.X, pos.Y) If pos.Y <= lv.Font.Height \ 2 Then ' Maus am oberen Ende des ListViews scrollDirection = 0 tmrLVScroll.Enabled = True ElseIf pos.Y >= lv.ClientSize.Height - lv.Font.Height \ 2 Then ' Maus am unteren Ende des ListViews scrollDirection = 1 tmrLVScroll.Enabled = True Else tmrLVScroll.Enabled = False End If e.Effect = DragDropEffects.Move pos.X = e.X pos.Y = e.Y pos = lv.PointToClient(pos) LVhoverItem = lv.GetItemAt(pos.X, pos.Y) ' -Start- Einzeichnen des Einfügepunkts in das ListView Dim g As Graphics = lv.CreateGraphics Dim c As Color = Color.Red Dim p As Pen p = New Pen(c, 2) ' Farbe und Dicke Dim s As SolidBrush s = New SolidBrush(c) ' Farbe If lv.View = View.Details Or lv.View = View.List Then ' für _: With LVhoverItem If .Index > SelIndex Then With .Bounds g.DrawLine(p, New Point(.X, .Y + .Height), _ New Point(.X + lv.Bounds.Width, .Y + .Height)) g.FillPolygon(s, New Point() { _ New Point(.X, .Y + .Height - 5), _ New Point(.X + 5, .Y + .Height), _ New Point(.X, .Y + .Height + 5)}) g.FillPolygon(s, New Point() { _ New Point(lv.Bounds.Width - 4, .Y + .Height - 5), _ New Point(lv.Bounds.Width - 9, .Y + .Height), _ New Point(lv.Bounds.Width - 4, .Y + .Height + 5)}) End With Else With .Bounds g.DrawLine(p, New Point(.X, .Y), _ New Point(.X + lv.Bounds.Width, .Y)) g.FillPolygon(s, New Point() { _ New Point(.X, .Y - 5), _ New Point(.X + 5, .Y), _ New Point(.X, .Y + 5)}) g.FillPolygon(s, New Point() { _ New Point(lv.Bounds.Width - 4, .Y - 5), _ New Point(lv.Bounds.Width - 9, .Y), _ New Point(lv.Bounds.Width - 4, .Y + 5)}) End With End If End With Else ' für |: With LVhoverItem If .Index > SelIndex Then With .Bounds g.DrawLine(p, New Point(.X + .Width, .Y), _ New Point(.X + .Width, .Y + .Height)) g.FillPolygon(s, New Point() { _ New Point(.X + .Width - 5, .Y), _ New Point(.X + .Width + 5, .Y), _ New Point(.X + .Width, .Y + 5)}) g.FillPolygon(s, New Point() { _ New Point(.X + .Width - 5, .Y + .Height), _ New Point(.X + .Width + 5, .Y + .Height), _ New Point(.X + .Width, .Y + .Height - 5)}) End With Else With .Bounds g.DrawLine(p, New Point(.X, .Y), _ New Point(.X, .Y + .Height)) g.FillPolygon(s, New Point() { _ New Point(.X - 5, .Y), _ New Point(.X + 5, .Y), _ New Point(.X, .Y + 5)}) g.FillPolygon(s, New Point() { _ New Point(.X - 5, .Y + .Height), _ New Point(.X + 5, .Y + .Height), _ New Point(.X, .Y + .Height - 5)}) End With End If End With End If ' -Ende- - Einzeichnen des Einfügepunkts in das ListView If IsNothing(LVhoverItem) Then Exit Sub If savedLVHoverIndex = LVhoverItem.Index Then Exit Sub lv.BeginUpdate() lv.EndUpdate() savedLVHoverIndex = LVhoverItem.Index End Sub Public Sub LV_ItemDrag(ByVal lv As ListView) SelIndex = lv.SelectedIndices(0) LVtmrParam = lv ' Drag&Drop starten lv.DoDragDrop(lv.SelectedItems, DragDropEffects.Move) End Sub Public Sub LV_DragLeave(ByVal lv As ListView) ' Löscht die Einfügemarke bei verlassen des ListViews lv.Invalidate() End Sub Private Sub ScrollControl(ByRef ctrl As Control, _ ByRef Direction As Integer) ' Ermöglicht scrollen während des Drag-Vorgangs Const WM_SCROLL As Integer = &H115S SendMessage(ctrl.Handle.ToInt32, WM_SCROLL, Direction, VariantType.Null) End Sub Private Sub tmrTick(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles tmrLVScroll.Tick ' Führt in definiertem Intervall den auto-scroll Vorgang aus ScrollControl(LVtmrParam, scrollDirection) End Sub End Module Dem Code Ihrer Form fügen Sie die folgenden 5 Ereignisprozeduren hinzu. Sie sind stark abstrahiert, so daß Sie jeweils nur mittels Handles - Anweisung ein oder mehrere ListViews und deren entsprechendes Ereignis mit den Prozeduren verknüpfen müssen, im folgenden nur für eine ListView mit dem Namen ListView1. Private Sub ListView_DragDrop(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) _ Handles ListView1.DragDrop Dim LV As ListView = DirectCast(sender, ListView) Call LV_DragDrop(LV, e) End Sub Private Sub ListView_DragEnter(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) _ Handles ListView1.DragEnter Call LV_DragEnter(e) End Sub Private Sub ListView_DragLeave(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles ListView1.DragLeave Dim LV As ListView = DirectCast(sender, ListView) Call LV_DragLeave(LV) End Sub Private Sub ListView_DragOver(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) _ Handles ListView1.DragOver Dim LV As ListView = DirectCast(sender, ListView) Call LV_DragOver(LV, e) End Sub Private Sub ListView_ItemDrag(ByVal sender As Object, _ ByVal e As System.Windows.Forms.ItemDragEventArgs) _ Handles ListView1.ItemDrag Dim LV As ListView = DirectCast(sender, ListView) Call LV_ItemDrag(LV) End Sub Um es an einem Beispiel zu demonstrieren fügen Sie Ihrer Form ein ListView (Name: ListView1) und zwei Buttons (Namen: Button1 und Button2) hinzu. Die 3 Ereignisprozeduren für das kleine Beispiel sehen wie folgt aus: Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ListView1.Columns.Add("Test") For i As Integer = 1 To 50 ListView1.Items.Add(i & i & i & i) Next ' Sonst kann kein Drag&Drop durchgeführt werden! ListView1.AllowDrop = True End Sub Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click ' Ansicht "Große Symbole" ListView1.View = View.LargeIcon End Sub Private Sub Button2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button2.Click ' Ansicht "Details" ListView1.View = View.Details End Sub Nun können Sie ein oder mehrere Elemente im ListView verschieben indem Sie sie einfach auf ein anderes Element (nicht auf einen Freiraum!) ziehen, die rote Markierung zeigt vorher jeweils an wo sie landen werden. Dieser Tipp wurde bereits 27.868 mal aufgerufen. Voriger Tipp | Zufälliger Tipp | Nächster Tipp
Anzeige
Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv Vol.6 (einschl. Beispielprojekt!) Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
vb@rchiv CD Vol.6 Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! Online-Update-Funktion Entwickler-Vollversionen u.v.m. Tipp des Monats Dezemeber 2024 Roland Wutzke MultiSort im ListView-Control Dieses Beispiel zeigt, wie sich verschiedene Sortierfunktionen für ein ListView Control realisieren lassen. Neu! sevCoolbar 3.0 Professionelle Toolbars im modernen Design! Mit sevCoolbar erstellen Sie in wenigen Minuten ansprechende und moderne Toolbars und passen diese optimal an das Layout Ihrer Anwendung an (inkl. große Symbolbibliothek) - für VB und MS-Access |
||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |