Problem: ListViewItem mit SubItems innerhalb eines ListViews per Drag&Drop verschieben

  • VB.NET

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von Scarala.

    Problem: ListViewItem mit SubItems innerhalb eines ListViews per Drag&Drop verschieben

    Hallo ihr lieben,

    ich stehe vor einem Problem.

    Ich habe ein ListView mit 3 Spalten. Ich möchte das sich die Items innerhalb des Listwiews incl. deren SubItems per Drag&Drop verschieben lassen.
    Zur Zeit löse ich das ganze mit Up- und Down-Buttons, was mir aber nicht wirklich zusagt.
    Ich habe schon hier im Forum und auch über Google ausgiebig gesucht, aber nichts passendes für mich gefunden.

    Ich hoffe mir ist zu helfen ;)

    LG

    Scarala
    Hi

    VB.NET-Quellcode

    1. 'Das ist das DragDrop-Format, das deine verschobenen Daten repraesentiert
    2. Public Const SomeFormat As String = "MyDataFormat"
    3. Private Sub _someListView_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles _someListView.DragDrop
    4. If e.Data.GetDataPresent(SomeFormat) Then
    5. 'Effekt auswaehlen (wenn das Element bewegt werden kann, wird es bewegt, ansonsten kopiert, falls das nicht klappt passiert nix)
    6. Dim effect As DragDropEffects = e.AllowedEffect And DragDropEffects.Move
    7. If effect = DragDropEffects.None Then effect = e.AllowedEffect And DragDropEffects.Copy
    8. e.Effect = effect
    9. If effect <> DragDropEffects.None Then
    10. 'SomeData-Daten ermitteln
    11. Dim data As SomeData = DirectCast(e.Data.GetData(SomeFormat), SomeData)
    12. Dim relativePosition As Point = _someListView.PointToClient(New Point(e.X, e.Y))
    13. Dim targetIndex As Integer
    14. Dim position As Point
    15. Dim item As ListViewItem
    16. 'je nach ListView-Modus Index des naechsten Elements ermitteln
    17. If _someListView.View = View.SmallIcon OrElse _someListView.View = View.LargeIcon Then
    18. item = _someListView.FindNearestItem(SearchDirectionHint.Left, relativePosition)
    19. If item Is Nothing Then
    20. item = _someListView.FindNearestItem(SearchDirectionHint.Up, relativePosition)
    21. End If
    22. Else
    23. item = _someListView.GetItemAt(relativePosition.X, relativePosition.Y)
    24. If item Is Nothing Then
    25. item = If(_someListView.Items.Count > 0, _someListView.Items(_someListView.Items.Count - 1), Nothing)
    26. End If
    27. End If
    28. If item Is Nothing Then
    29. targetIndex = 0
    30. position = Point.Empty
    31. Else
    32. Dim itemRectangle As Rectangle = item.Bounds
    33. targetIndex = item.Index
    34. 'position soll die Position des einzufuegenden Items im ListView angeben
    35. If _someListView.View = View.Details OrElse _someListView.View = View.List Then 'In der Listendarstellung wird in Abh. von y der Index erhoeht
    36. If relativePosition.Y > itemRectangle.Top + itemRectangle.Height \ 2 Then 'ist die Mausposition unterhalb der Item-Mitte
    37. targetIndex += 1 'wird das Item NACH dem Item an der Position eingefuegt
    38. position = New Point(itemRectangle.Left, itemRectangle.Bottom)
    39. Else
    40. 'sonst davor
    41. position = New Point(itemRectangle.Left, itemRectangle.Top)
    42. End If
    43. Else
    44. 'sonst wird das gleiche analog fuer x durchgefuehrt
    45. If relativePosition.X > itemRectangle.Left + itemRectangle.Width \ 2 Then
    46. targetIndex += 1
    47. position = New Point(itemRectangle.Right, itemRectangle.Top)
    48. Else
    49. position = New Point(itemRectangle.Left, itemRectangle.Top)
    50. End If
    51. End If
    52. End If
    53. 'wuerde theoretisch auch fuer SmallIcon/LargeIcon klappen, tut es aber nicht, da der index nicht die Position im ListView angibt
    54. item = _someListView.Items.Insert(targetIndex, New DataListViewItem(data))
    55. item.Position = position
    56. End If
    57. End If
    58. End Sub
    59. Private Sub _someListView_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles _someListView.DragOver
    60. If e.Data.GetDataPresent(SomeFormat) Then e.Effect = e.AllowedEffect And DragDropEffects.Move
    61. End Sub
    62. Private Sub _someListView_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles _someListView.MouseMove
    63. If (e.Button And Windows.Forms.MouseButtons.Left) = Windows.Forms.MouseButtons.Left Then
    64. Dim data As New System.Windows.Forms.DataObject()
    65. Dim item As DataListViewItem = DirectCast(_someListView.FocusedItem, DataListViewItem)
    66. data.SetData(SomeFormat, item.Data)
    67. Dim effect As DragDropEffects = _someListView.DoDragDrop(data, DragDropEffects.Link Or DragDropEffects.Copy Or DragDropEffects.Move)
    68. If effect = DragDropEffects.Move Then
    69. item.Remove()
    70. End If
    71. End If
    72. End Sub
    73. Private Class DataListViewItem
    74. Inherits ListViewItem
    75. Private _data As SomeData
    76. Public Property Data As SomeData
    77. Get
    78. Return _data
    79. End Get
    80. Set(ByVal value As SomeData)
    81. If value Is Nothing Then Throw New ArgumentException("Data mustnot be null.")
    82. SubItems.Clear()
    83. If value.Data IsNot Nothing Then
    84. SubItems.AddRange(value.Data)
    85. End If
    86. Text = value.Identifier
    87. _data = value
    88. End Set
    89. End Property
    90. Public Sub New(ByVal identifier As String, ByVal data() As String)
    91. Me.Data = New SomeData(identifier, data)
    92. End Sub
    93. Public Sub New(ByVal data As SomeData)
    94. Me.Data = data
    95. End Sub
    96. End Class
    97. <Serializable()> _
    98. Public Class SomeData
    99. Implements System.Runtime.Serialization.ISerializable
    100. Private ReadOnly _identifier As String
    101. Private ReadOnly _data() As String
    102. Public ReadOnly Property Data As String()
    103. Get
    104. Return _data
    105. End Get
    106. End Property
    107. Public ReadOnly Property Identifier As String
    108. Get
    109. Return _identifier
    110. End Get
    111. End Property
    112. Public Sub New(ByVal identifier As String, ByVal data() As String)
    113. If identifier Is Nothing Then Throw New ArgumentNullException("identifier")
    114. _identifier = identifier
    115. _data = data
    116. End Sub
    117. Protected Overridable Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
    118. info.AddValue("Data", Data)
    119. info.AddValue("Identifier", Identifier)
    120. End Sub
    121. Protected Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)
    122. Me.New(DirectCast(info.GetValue("Identifier", GetType(String)), String), DirectCast(info.GetValue("Data", GetType(String())), String()))
    123. End Sub
    124. End Class

    Der Serialisierungs-Support ist nicht notwendig, aber ich hab' ihn trotzdem mal reingepackt. Wahrscheinlich sieht das bei dir eh ganz anders aus.
    Statt den Standard-ListViewItems musst du dann halt DataListViewItems hinzufügen.

    Gruß
    ~blaze~