DGV Sort Problem mit Selektion

  • VB.NET

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von Peter329.

    DGV Sort Problem mit Selektion

    Hi,

    ich habe eine Datagridview .... die hat den SelectionMode "FullRowsSelect", MulitiRowSelect ist false, die Row Header sind nicht sichtbar und man kann die dgv sortieren.

    Wenn eine Zeile ausgewählt ist, und ich den Header einer Spalte anklicke, dann wird nach dieser Spalte sortiert und die ausgewählte Zeile bleibt selektiert.

    So far so good !

    Ich kann aber auch die Selektion der Zeile aufheben, indem ich mit der rechten Mouse die dgv klicke ... dann wird ein dgv.ClearSelection ausgeführt und keine Zeile ist ausgewählt.

    Wenn ich jetzt den Header einer Spalte anklicke, wird zwar sortiert ... aber ... die vormals ausgewählte Zeile, wird erneut ausgewählt. Die Selection erscheint sozusagen wie ein Phoenix aus der Asche !

    Ich hab das folgende Coding, um den Effekt zu demonstrieren:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. DataGridView1.Rows.Add("A")
    4. DataGridView1.Rows.Add("B")
    5. DataGridView1.Rows.Add("C")
    6. DataGridView1.Rows.Add("D")
    7. DataGridView1.Rows.Add("E")
    8. DataGridView1.Rows.Add("F")
    9. DataGridView1.Rows.Add("G")
    10. DataGridView1.Rows.Add("H")
    11. End Sub
    12. Private Sub DataGridView1_MouseClick(sender As Object, e As MouseEventArgs) Handles DataGridView1.MouseClick
    13. Dim i As Integer = -1
    14. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    15. Debug.Print("MouseClick: i=" & i.ToString)
    16. If e.Button = MouseButtons.Right Then DataGridView1.ClearSelection()
    17. End Sub
    18. Private Sub DataGridView1_Sorted(sender As Object, e As EventArgs) Handles DataGridView1.Sorted
    19. Dim i As Integer = -1
    20. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    21. Debug.Print("Sorted: i=" & i.ToString)
    22. End Sub
    23. Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) Handles DataGridView1.SelectionChanged
    24. Dim i As Integer = -1
    25. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    26. Debug.Print("SelectionChanged: i=" & i.ToString)
    27. End Sub
    28. Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
    29. Dim i As Integer = -1
    30. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    31. Debug.Print("ColumnHeaderMouseClick: i=" & i.ToString)
    32. End Sub


    Zunächst wähle ich die Zeile mit i=2 aus, die enthält den Buchstaben "C". (s.SortDgv01.jpg)
    Debug.Print zeigt:

    SelectionChanged: i=2

    Ich drücke dann die rechte Maustaste und löse damit DatagridView1.ClearSelection() aus. (s. SortDgv02.jpg)
    Debug.Print zeigt

    MouseClick: i=2
    SelectionChanged: i=-1
    MouseClick: i=-1

    Jetzt klicke ich den Header der ersten und einzigen Spalte ... die Sortierung wird umgekehrt und die Selection der Zeile mit i=2 wird restauriert !!!!! (s. SortDgv03.jpg)

    Debug.Print zeigt:
    SelectionChanged: i=5
    Sorted: i=5
    ColumnHeaderMouseClick: i=5

    i=5 ist der Index der Zeile, die "C" enthält, NACH der Sortierung. Und diese Selection wird ausgelöst, bevor das Ereignis "Sorted" ausgeführt wird.

    Ich hoffe, ihr habt mir folgen können.

    Irgendwo muss sich .NET die einstmals selektierte Zeile merken und die Selektion nach dem Sort wieder restaurieren.

    Vermutlich ist die Sache ganz einfach ... aber ich komme ums Verplatzen nicht drauf, wo der Fehler liegt.

    Kann mir jemand nachsichtig helfen ?

    LG
    Peter
    Bilder
    • SortDgv03.jpg

      14,35 kB, 273×307, 65 mal angesehen
    • SortDgv02.jpg

      11,1 kB, 273×307, 67 mal angesehen
    • SortDgv01.jpg

      11,22 kB, 273×307, 65 mal angesehen
    @Peter329 Dann lösch doch nach dem Sortieren die Selektion erneut.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Dann lösch doch nach dem Sortieren die Selektion erneut.


    Na ja, das könnte ich machen. Etwa am Ende des Event "ColumnHeaderMouseClick" die Selection löschen

    Aber wenn eine Zeile vor dem Klick auf dem ColumnHeader ausgewählt war, dann soll diese Auswahl natürlich auch nach dem Sort erhalten bleiben. So wie es ja auch standardmäßig der Fall ist. Also "generell" die Auswahl zu löschen ist keine Lösung.

    Ich müsste halt eine Möglichkeit finden, zu unterscheiden, ob die Zeile zu "Recht" oder zu "Unrecht" nach dem Sort ausgewählt ist ! Und nur im zweiten Fall darf ich die Auswahl mit ClearSelection() entfernen.

    Allerdings habe ich nichts gefunden, wie ich diesen Unterschied feststellen könnte.

    LG
    Peter

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

    Setz einfach im DataGridView1_MouseClick-EventHandler zusammen mit ClearSelection DataGridView1.CurrentCell = Nothing
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Peter329 schrieb:

    zu "Recht" oder zu "Unrecht"
    Das ließe sich mit einem Flag abfangen (Boolean Variable).
    Wenn der Vorschlag von @VaporiZed funktioniert, brauchst Du das natürlich nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    VaporiZed schrieb:

    DataGridView1.CurrentCell = Nothing


    Das hab ich ausprobiert.

    Es verändert sich etwas: wenn vor dem Sort keine Zeile ausgwählt wurde, dann wird jetzt die ERSTE bzw LETZTE Zeile im Wechsel ausgewählt.

    So ganz hilft das also nicht weiter.

    RodFromGermany schrieb:

    Das ließe sich mit einem Flag abfangen (Boolean Variable).


    Ja klar, ein Flag könnte helfen. Nur WO (also in welchem Ereignis) setze ich dieses Flag ? Und WELCHE Eigenschaften bestimmen den Wert des Flags ?

    LG
    Peter
    Ich hab mal meinen EventHandler-Generator angeworfen. Das erste Event, welches nach dem Sortieren gefeuert wird und dann die SelectedRow wiederherstellt ist das Rowstatechanged-Event. Dementsprechend könntest Du dort ansetzen und ggf. ClearSelection aufrufen, wenn bei HeaderClick noch SelectedRows.Count = 0 war. Aber ich habe keine Möglichkeit bei mir gefunden, nach dem Sortieren gar keine selektierte Row zu haben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @Peter329 Da, wo Du die Selektierung löschst, wird das Flag gesetzt.
    Wo eine Zelle / Zeile selektiert wird, wird das Flag gelöscht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich hab dir ein "hilfreich" spendiert, einfach deshalb, weil du (wie so oft) so freundlich warst und dich mit meinem Problem beschäftigst hast. Aber so einfach lässt sich mein Problem leider nicht lösen.

    Klar Ich könnte in der Routine "SelectionChanged" ein Flag setzen, abhängig davon, ob eine Zeile selektiert wurde oder nicht.

    Aber jetzt schau dir mal den o.a. Event Ablauf an, wenn ich den Column Header der DGV anklicke:

    SelectionChanged .... (hier wird die vom Sort ausgewählte Zeile aktiviert)
    Sorted .... (das Ende der Sort Operation)
    ColumnHeaderMouseClick ... (hier könnte ich jetzt das Flag auswerten)

    Aber wie man sieht: Wenn ich im SelectionChanged Event ein Flag setze, dann wird dies gleich nach dem Clicken des ColumnHeaders ÜBERSCHRIEBEN ! Und damit scheitert dieser Lösungsansatz.

    Ich habe versucht, ob man herausfinden kann, ob das SelectionChanged Event vom Sort ausgelöst wurde (um es zu ignorieren) und deshalb in die SelectionChanged Event Routine die folgende Anweisung eingefügt:

    VB.NET-Quellcode

    1. Debug.Print("SelectionChanged sender: " & " - " & sender.ToString)


    Egal wie die Selection geändert wird, ich erhalte:

    Quellcode

    1. SelectionChanged sender: - System.Windows.Forms.DataGridView


    Und damit bin ich (wieder mal) am Ende mit meinem Latein!

    Ich hoffe, ich habe das Problem verständlich machen können ....

    LG
    Peter

    {edit]

    Ich habe eben erst den Beitrag von Vaporized entdeckt:

    Zitat: Aber ich habe keine Möglichkeit bei mir gefunden, nach dem Sortieren gar keine selektierte Row zu haben.

    Also das ist doch kein Problem: Einfach in der ColumnHeaderMouseClick Event Routine die Anweisung DataGridView1.ClearSelection() einfügen ... und schon ist nach dem Sort nix mehr selektiert.

    Das mit dem RowStateChanged schaue ich mir jetzt mal in Ruhe an .... möglichweise könnte das eine Möglichkeit sein !



    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Peter329“ ()

    @Peter329 An welcher Stelle löschst Du denn die Selektierung?
    Wie bettet sich das in die Event-Folge?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also, das Problem sollte doch klar sein:

    Wenn ich eine Zeile der DatagridView auswähle, und dann sortiere, dann soll die Selektion ERHALTEN bleiben. Das ist standardmäßig der Fall ... da muss man also nichts ändern.

    Wenn ich KEINE Zeile auswähle, dann soll nach dem Sort auch KEINE Zeile ausgewählt sein. Das ist aber NICHT der Fall. Sondern es wird eine Zeile in der sortierten DGV selektiert. (S. Vor dem Sort.jpg und Nach dem Sort.jpg)

    MIt dem hier eingestellten Beispiel Coding kann man diese Effekte nachvollziehen.

    Also deutlicher kann ich mein Problem nicht beschreiben !

    Meine Forderung ist doch nichts Ungewöhnliches. Dieses Verhalten dürften doch die meisten Menschen von einer Datagrid View erwarten ! Ich bin am verzweifeln mit dem .Net !

    LG
    Peter
    Bilder
    • Vor dem Sort.jpg

      9,36 kB, 250×294, 63 mal angesehen
    • Nach dem Sort.jpg

      9,45 kB, 250×294, 63 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Peter329“ ()

    @Peter329 Das Problem ist klar, nicht jedoch Deine Umsetzung.
    Kannst Du mal ein kleines Demoprojekt posten?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Man braucht ein Form1 mit einer DatagridView1 und einer Column1 ...

    Die DGV hat keine RowHeader, SelectionMode=FullRowselect und multirowselect=False

    Hier ist das Coding:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. DataGridView1.Rows.Add("A")
    4. DataGridView1.Rows.Add("B")
    5. DataGridView1.Rows.Add("C")
    6. DataGridView1.Rows.Add("D")
    7. DataGridView1.Rows.Add("E")
    8. DataGridView1.Rows.Add("F")
    9. DataGridView1.Rows.Add("G")
    10. DataGridView1.Rows.Add("H")
    11. End Sub
    12. Private Sub DataGridView1_MouseClick(sender As Object, e As MouseEventArgs) Handles DataGridView1.MouseClick
    13. Dim i As Integer = -1
    14. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    15. Debug.Print("MouseClick: i=" & i.ToString)
    16. If e.Button = MouseButtons.Right Then
    17. DataGridView1.ClearSelection() 'Right mouse click on DGV clears selection
    18. DataGridView1.CurrentCell = Nothing
    19. End If
    20. End Sub
    21. Private Sub DataGridView1_Sorted(sender As Object, e As EventArgs) Handles DataGridView1.Sorted
    22. Dim i As Integer = -1
    23. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    24. Debug.Print("Sorted: i=" & i.ToString)
    25. End Sub
    26. Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) Handles DataGridView1.SelectionChanged
    27. Debug.Print("SelectionChanged sender: " & " - " & sender.ToString)
    28. Dim i As Integer = -1
    29. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    30. Debug.Print("SelectionChanged: i=" & i.ToString)
    31. End Sub
    32. Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
    33. Dim i As Integer = -1
    34. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    35. Debug.Print("ColumnHeaderMouseClick: i=" & i.ToString)
    36. 'DataGridView1.ClearSelection() 'This will deselect after sort at ANY rate (this is NO solution)
    37. End Sub
    38. Private Sub DataGridView1_RowStateChanged(sender As Object, e As DataGridViewRowStateChangedEventArgs) Handles DataGridView1.RowStateChanged
    39. Dim i As Integer = -1
    40. If DataGridView1.SelectedRows.Count > 0 Then i = DataGridView1.SelectedRows(0).Index
    41. Debug.Print("RowStateChanged: i=" & i.ToString)
    42. End Sub
    43. End Class

    @Peter329 Hab mal fix was verbrochen, neue Form, CheckBox, DGV:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private noSelection As Boolean = False
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Me.DataGridView1.Rows.Add(3)
    5. Me.DataGridView1.Rows(0).Cells(0).Value = "aa"
    6. Me.DataGridView1.Rows(1).Cells(0).Value = "bb"
    7. Me.DataGridView1.Rows(2).Cells(0).Value = "cc"
    8. Me.DataGridView1.Rows(0).Cells(1).Value = "cc"
    9. Me.DataGridView1.Rows(1).Cells(1).Value = "bb"
    10. Me.DataGridView1.Rows(2).Cells(1).Value = "aa"
    11. Me.DataGridView1.Rows(0).Cells(2).Value = "aa"
    12. Me.DataGridView1.Rows(1).Cells(2).Value = "cc"
    13. Me.DataGridView1.Rows(2).Cells(2).Value = "bb"
    14. End Sub
    15. Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
    16. noSelection = CheckBox1.Checked
    17. If noSelection Then
    18. DataGridView1.ClearSelection()
    19. DataGridView1.CurrentCell = Nothing
    20. End If
    21. End Sub
    22. Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) Handles DataGridView1.SelectionChanged
    23. If noSelection Then
    24. DataGridView1.ClearSelection()
    25. DataGridView1.CurrentCell = Nothing
    26. End If
    27. End Sub
    28. End Class

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Na gut ... jetzt kannst du mit der CheckBox1 generell die Selektion verhindern. (Da brauchst du doch nicht einmal einen Schalter, sondern könntest direkt CheckBox1.Selected abfragen !)

    Aber hilft das etwas bei meinem Problem ? Wenn es nur darum geht, die Selektion manuell aufzuheben, dann kann ich doch ganz einfach nach dem Sort einen RechtsClick mit der Mouse ausführen ! Dazu brauche ich keine CheckBox !

    LG
    Peter
    Ich bin jetzt zumindest so weit, dass ich mit meinem EventHandler-Generator/-Tracker sagen kann, dass beim CellEnter-EventHandler SelectedRows.Count noch 0 ist und danach ein RowStateChanged kommt, bei dem Count = 1 ist. Das sind also die EventHandler bei denen Du ein Flag ansetzen könntest.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Peter329 schrieb:

    Aber hilft das etwas bei meinem Problem ?
    Was an Deinem Problem wird denn nicht erfüllt?
    Die CheckBox ist nur ein Q&D Mittel zum Zweck, deswegen gibt es auch die separate Boolean-Variable
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Probier das mal:

    VB.NET-Quellcode

    1. Private SelectionIsAllowed As Boolean = True
    2. Private Trace As Boolean = False
    3. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. DataGridView1.Rows.Add("F")
    5. DataGridView1.Rows.Add("C")
    6. DataGridView1.Rows.Add("Q")
    7. DataGridView1.Rows.Add("E")
    8. DataGridView1.Rows.Add("H")
    9. End Sub
    10. Private Sub DataGridView1_CellEnter(sender As Object, e As EventArgs) Handles DataGridView1.CellEnter
    11. If Trace AndAlso DataGridView1.SelectedRows.Count = 0 Then SelectionIsAllowed = False
    12. End Sub
    13. Private Sub DataGridView1_RowStateChanged(sender As Object, e As EventArgs) Handles DataGridView1.RowStateChanged
    14. If Not SelectionIsAllowed Then DataGridView1.ClearSelection() : DataGridView1.CurrentCell = Nothing
    15. End Sub
    16. Private Sub DataGridView1_MouseClick(sender As Object, e As MouseEventArgs) Handles DataGridView1.MouseClick
    17. If e.Button = MouseButtons.Right Then DataGridView1.ClearSelection()
    18. End Sub
    19. Private Sub FrmMain_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    20. Trace = True
    21. End Sub
    22. Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
    23. SelectionIsAllowed = True
    24. End Sub
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    [edit] Ich ersetze jetzt einfach mal mein Posting ... weil sich die Verhältnisse geändert haben ... :)

    Ich habe dein Coding ausprobiert ... und siehe da, es funktioniert ! YEHEY !

    Ok ... jetzt muss erst noch herausfinden, WARUM das funktioniert ... der Schlüssel liegt wohl darin, dass man beim CellEnter mitbekommt, dass keine Zeile ausgewählt wurde ... und dieses Wissen muss man dann sorgfältig über ein Flag propagieren !

    Zunächst mal recht herzlichen Dank an die Ratgeber, die so unendlich freundlich waren, sich mit meinem kniffligen Problem eingehend zu beschäftigen. Ich schau mir die Lösung jetzt an ... und gebe natürlich Rückmeldung !

    LG
    Peter

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Peter329“ ()

    Hab jetzt noch rausgefunden, dass nach ClearSelection und CurrentCell = Nothing die erste Zelle selektiert wird, wenn das DGV wieder den Focus erhält, also z.B. durch den ColumnHeaderClick. Das erklärt, warum dann das von Dir gesehene Verhalten auftritt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.