drag & drop mehrere Zeile im Datagridview

  • VB.NET
  • .NET (FX) 4.0

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    drag & drop mehrere Zeile im Datagridview

    Hallo Alle ,
    ich das Problem wurde bereits in mehrere Foren gestellt. Aber zurzeit habe ich keine richtige Antwort gefunden.
    Ich möchte im Rahmen eines Projektes ein Explorer- Ansicht ähnlich wie die von Windows erstellen. Ich wollte
    das Datagridview an der Stelle des Listviews nutzen, um die Sortierungeigenschaft des gridviews zu nutzen.

    Hat jemand ein Beispiel oder eine Vorgehensweise wie man mehrere gewählter Zeile eines datagridviews per Drag & drop verschieben kann?
    bisher kriege ich komische Verhalten, wenn ich in der Mousedown- Event er drag&drop-Vorgang starte.

    danke im voraus

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Arist4“ ()

    Das fällt unter Draggen innerhalb der Anwendung. Dabei ist das DataObject mehr hinderlich als nützlich.
    aber ich hab nur ein tutorial für c#: mycsharp.de/wbb2/thread.php?threadid=73005%0D%0A

    Und für DGV hat man zusätzlich das Problem, dass die Multi-Selection mittm MouseDown verloren geht. Also muss man sie sich im PreviewMouseDown merken, und im MouseDown wieder herstellen.

    Oder willst du auch in annere Anwendungen hinein-draggen? Dann ist das DataObject natürlich zu benützen, und dann passt dieses Tut: DragDrop-Sample
    @ ErfinderDesRades
    zuerst danke für deine Antwort.

    ErfinderDesRades schrieb:

    Und für DGV hat man zusätzlich das Problem, dass die Multi-Selection mittm MouseDown verloren geht. Also muss man sie sich im PreviewMouseDown merken, und im MouseDown wieder herstellen.
    .
    Genau hier liegt mein Problem. wenn mehrere Zeilen gewählt sind und man auf irgendeine gewählte Zeile drückt um den Vorgang zu starten( mousedown), geht die Selektion der anderen Zeilen verloren. Alle was ich in Internet als Code gesehen habe funktioniert nicht.
    Oder willst du auch in annere Anwendungen hinein-draggen?

    In meinem Gridview habe ich eine Spalte id und werde für jede gewählte Zeile, den Wert der Zelle id in einem Array speichern. Die gefüllte Array brauche ich dann für den dragdrop-Vorgang eines anderen Steuerelements. Ich weiß aber bereits wie ich hier vorgehen soll.
    kannst du mir bitte erklären wie ich vorgehen soll? (Drag mehrere Zeile )
    danke

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Arist4“ ()

    naja - prinzipiell hab ichs dir doch mitgeteilt: Merke dir die Selection, bevor sie zerstört wird.
    Nur mittm PreviewMouseDown-Event habich geirrt: das gibts im WinForms-DGV nicht.

    Aber hab grad getestet: hierfür ist auch das MouseDown-Event geeignet.

    Und stell die Selection wieder her, nachdem sie zerstört wurde.
    nö.

    Das Thema kann man einfach abhandeln, dann langts vorne und hinten nicht für eine sinnvolle Verwendung.

    oder man handelts "alles erschlagend" ab - wie im gegebenen c#-Tutorial, dann verstehts kein Mensch.

    Etwa bei deiner Anforderung: Da muss ja auch ein Highlighting stattfinden über dem Ziel-Control. Damit der User sieht, wo die gedraggten Inhalte eingefügt werden.
    Allein so ein Highlighter ist ein Thema für sich.
    also ich hab jetzt was gebastelt, was das Multi-Item-Problem beim DragStart lösen täte.
    Aber wie gesagt, das hat kein Sinn, weil ich noch kein Target-Highlighting dran hab.
    Also Frage, ob du Targethighlighting brauchst.
    Targethighlighting brauchst du, wenn dein Drag-Ziel ebenfalls ein Multi-Item-Control ist, etwa Datagridview oder Listbox oder sowas.
    Weil da will man ja normal nicht nur reinschmeißen, sondern auch zielen können, hinter/vor welchem Item der Drag eingefügt werden soll.
    Also brauchst du Target-Highlighting?
    @ ErfinderDesRades

    Zuerst danke für deine Hilfe. Mein Ziel-Control ist ein Treeview ( Also keine Multi-Item) . Ich brauche ein Target-Highlighting ich kann aber selbst basteln. Wichtig ist vor allem diese Multi-Select Eingenschaft mit Drag lösen zu können.

    kannst du mir bitte deine Vorgehenweise erklären?

    Danke nochmals
    natürlich ist ein Treeview ein Multi-Item-Control - Item heißt "Dingens", und ein Treenode ist doch ein Dingens, und davon gibts viele.
    Wie gesagt: Im DGV.MouseDown musste dir die Selection merken, weil gleich anschließend verfällt die.
    Kurzdarauf erfolgt der Dragstart, und in dem Moment musste die Selection wieder herstellen, damit du das Dgv mit Selection dann im DragDrop verarbeiten kannst.
    Was du nicht brauchst, ist das DataObject.
    Im DataObject sind Daten untypisiert und umständlich hinterlegt. Du aber hast dir das Dgv inklusive seiner Selection ja typisiert gemerkt, bzw. weißt sowieso, um welches Dgv es geht.
    Also wozu Daten ins DataObject praktizieren, und wieder rausfummeln und casten (und dabei gibts paar Fußangeln), wenn du die Daten doch eh schon lange kennst??

    Ich hab ein TestProjekt gebastelt, aber leider kann ichs nicht anhängen.
    Aber der Code ist nicht weiter wild, also halt so:

    VB.NET-Quellcode

    1. Public Class DgvSelectionStore
    2. Private WithEvents _Dgv As DataGridView
    3. Public Sub New(ByVal dgv As DataGridView)
    4. _Dgv = dgv
    5. End Sub
    6. Public Bands As New List(Of DataGridViewBand)
    7. Public Cells As New List(Of DataGridViewCell)
    8. Private Sub ItemDataGridView_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles _Dgv.MouseDown
    9. Bands.Clear() : Cells.Clear()
    10. _Dgv.SelectedRows.Cast(Of DataGridViewBand).ForEach(AddressOf Bands.Add)
    11. _Dgv.SelectedColumns.Cast(Of DataGridViewBand).ForEach(AddressOf Bands.Add)
    12. _Dgv.SelectedCells.Cast(Of DataGridViewCell).ForEach(AddressOf Cells.Add)
    13. End Sub
    14. Public Sub Restore()
    15. _Dgv.ClearSelection()
    16. Bands.ForEach(Sub(itm) itm.Selected = True)
    17. Cells.ForEach(Sub(itm) itm.Selected = True)
    18. End Sub
    19. End Class

    VB.NET-Quellcode

    1. Imports DragjobTester.ItemsDts
    2. Imports System.IO
    3. Public Class frmStandardDrag
    4. Private _DgvSelectionStore As DgvSelectionStore
    5. Private _DragStart As Point
    6. Private Shared _DummiData As New DataObject
    7. Public Sub New()
    8. InitializeComponent()
    9. _DgvSelectionStore = New DgvSelectionStore(ItemDataGridView)
    10. GenerateData()
    11. TreeView1.ExpandAll()
    12. End Sub
    13. Private Sub GenerateData()
    14. For i = 0 To 9
    15. ItemsDts.Item.AddItemRow("col1_" & i, "col2_" & i)
    16. Next
    17. End Sub
    18. Private Sub ItemDataGridView_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles ItemDataGridView.MouseDown
    19. If e.Button <> Windows.Forms.MouseButtons.Left Then Return
    20. _DragStart = e.Location
    21. End Sub
    22. Private Sub ItemDataGridView_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles ItemDataGridView.MouseMove
    23. If e.Button <> Windows.Forms.MouseButtons.Left Then Return
    24. With e.Location 'draggen erst starten, wenn ein kleines Stück mit gehaltener Maustaste gezogen wurde
    25. If (.X - _DragStart.X) ^ 2 + (.Y - _DragStart.Y) ^ 2 > 9 Then
    26. _DgvSelectionStore.Restore()
    27. Dim result = ItemDataGridView.DoDragDrop(_DummiData, DragDropEffects.Copy)
    28. If result <> DragDropEffects.None Then
    29. ' Hier Drop-Aktion ausführen - ***nicht*** im Treeview.DragDrop-Event!!!
    30. Dim nd = TreeView1.GetNodeAt(TreeView1.PointToClient(Control.MousePosition))
    31. MessageBox.Show("dropped on: " & nd.Text)
    32. End If
    33. Highlighter.Off()
    34. End If
    35. End With
    36. End Sub
    37. Private Sub TreeView1_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles TreeView1.DragOver
    38. Dim nd = TreeView1.GetNodeAt(TreeView1.PointToClient(Control.MousePosition))
    39. If nd Is Nothing Then
    40. Highlighter.Off()
    41. e.Effect = DragDropEffects.None
    42. Else
    43. e.Effect = DragDropEffects.Copy
    44. Highlighter.Highlight(TreeView1, nd.Bounds)
    45. End If
    46. End Sub
    47. End Class
    Also der DgvSelectionStore merkt sich automatisch bei jedem MouseDown die Selection. Nur zum Wiederherstellen musste ihn explizit auffordern - nämlich wenn das Draggen tatsächlich beginnt.

    Ach - hier noch der Nodehighlighter:

    VB.NET-Quellcode

    1. Imports System.Drawing
    2. Imports System.Windows.Forms
    3. '''<summary> Zum Highlighten von Treenodes, ListviewItems etc. </summary>
    4. Public Class Highlighter
    5. ' Das Highlighten erfolgt durch Farb-Inversion des Target-Rectangles. Ausschalten
    6. ' des Highlights durch wiederholte Inversion desselben Rectangles. Fehl-Highlighting
    7. ' ergibt sich also, wenn zwischen Highlight() und Off() das Rectangle anderweitig
    8. ' übermalt wurde.
    9. Protected Shared _HighlightedRect As Rectangle = Rectangle.Empty
    10. ' Farb-Inversion ist eine Art "Spiegelung" über eine Farb-Achse.
    11. ' Dieses komische Rot ergibt (bisher) immer deutliche "Spiegel-Farben"
    12. Private Shared ReadOnly _AxisColor As Color = Color.FromArgb(255, 0, 127)
    13. Public Shared Sub Highlight(ByVal Target As Control, ByVal ItemRect As Rectangle)
    14. If ItemRect.IsEmpty Then
    15. Highlighter.Off()
    16. Else
    17. ItemRect.Intersect(Target.ClientRectangle)
    18. ' FillReversibleRectangle verwendet bildschirmbezogene Koordinaten, daher muß ItemRect
    19. ' um die Bildschirmposition des Controls verschoben werden
    20. ItemRect.Offset(Target.PointToScreen(Point.Empty))
    21. If ItemRect.IntersectsWith(_HighlightedRect) Then
    22. Return
    23. End If
    24. ' ist schon highlighted
    25. If Not _HighlightedRect.IsEmpty Then
    26. ' altes Highlight löschen
    27. ControlPaint.FillReversibleRectangle(_HighlightedRect, _AxisColor)
    28. End If
    29. _HighlightedRect = ItemRect
    30. ' neues Highlight setzen
    31. ControlPaint.FillReversibleRectangle(ItemRect, _AxisColor)
    32. End If
    33. End Sub
    34. Public Shared Sub Before(ByVal Target As Control, ByVal ItemRect As Rectangle)
    35. ItemRect.Offset(0, -ItemRect.Height \ 2)
    36. ItemRect.Inflate(0, -2)
    37. Highlight(Target, ItemRect)
    38. End Sub
    39. Public Shared Sub After(ByVal Target As Control, ByVal ItemRect As Rectangle)
    40. ItemRect.Offset(0, ItemRect.Height)
    41. Before(Target, ItemRect)
    42. End Sub
    43. Public Shared Sub FullWidth(ByVal Target As Control, ByVal Y As Integer, ByVal Height As Integer)
    44. 'bei leeren ListenControls, oder bei Treeview.TopLevel als Ziel kann kein ItemRect angegeben werden
    45. Highlighter.Highlight(Target, New Rectangle(0, Y, Target.Width, Height))
    46. End Sub
    47. Public Shared Sub Off()
    48. If _HighlightedRect.IsEmpty Then
    49. Return
    50. End If
    51. ControlPaint.FillReversibleRectangle(_HighlightedRect, _AxisColor)
    52. _HighlightedRect = Rectangle.Empty
    53. End Sub
    54. End Class
    Aber den brauchst du ja gar nicht (hihi - wenn du dich da man nicht irrst)
    Ups - da fehlt noch die Foreach - Extension.

    VB.NET-Quellcode

    1. Public Module CollectionX
    2. <DebuggerStepThrough(), Extension()> _
    3. Public Sub ForEach(Of T)(ByVal items As IEnumerable(Of T), ByVal Action As Action(Of T))
    4. For Each itm In items
    5. Action(itm)
    6. Next
    7. End Sub
    8. End Module
    Oder bastel die entsprechenden Stellen in richtige Foreach-Schleifen um

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hallo Erfinder des Rades
    ist zwar schon eine Zeitlang her dein Posting, aber ich hoffe du kannst vielleicht doch noch das komplette Testprojekt posten. Ich komme mit den Codeschnipseln nicht ganz klar. Wo finde ich z.B.
    Imports DragjobTester.ItemsDts
    Ich habe versucht den Code in eine Form zu kopieren. Bekomme aber nur Fehlermeldungen.

    Gruß
    Hallihallo