vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
sevDataGrid - Gönnen Sie Ihrem SQL-Kommando diesen krönenden Abschluß!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Controls · ListView & TreeView   |   VB-Versionen: VB.NET25.02.08
Drag & Drop in ListView (.NET)

Verschieben der Items innerhalb eines ListView-Controls

Autor:   Andreas HuhnBewertung:     [ Jetzt bewerten ]Views:  27.475 
www.andreashuhn.deSystem:  WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 Beispielprojekt auf CD 

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.475 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!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.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
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.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel