vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Sch?tzen Sie Ihre Software vor Software-Piraterie - mit sevLock 1.0 DLL!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2015
 
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:  17.899 
www.andreashuhn.deSystem:  WinNT, Win2k, WinXP, Vista, Win7, Win8, Win10 Beispielprojekt auf CD 

Summer-Special bei Tools & Components!
Gute Laune Sommer bei Tools & Components
Top Summer-Special - Sparen Sie teilweise über 100,- EUR
Alle sev-Entwicklerkomponenten und Komplettpakete jetzt bis zu 25% reduziert!
zum Beispiel:
  • Developer CD nur 455,- EUR statt 569,- EUR
  • sevDTA 2.0 nur 224,30 EUR statt 299,- EUR
  •  
  • vb@rchiv   Vol.6 nur 18,70 EUR statt 24,95 EUR
  • sevCoolbar 3.0 nur 58,70 EUR statt 69,- EUR
  • - Werbung -Und viele weitere Angebote           Aktionspreise nur für kurze Zeit gültig

    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 17.899 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-2015 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