Spaltensortierung im DataGridView

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von us4711.

    Spaltensortierung im DataGridView

    Es liegt ein typisiertes Dataset mit zwei Tabellen vor:

    Die Anbindung der Tabellen erfolgt über BindingSources.
    Tabelle Material wird in einem DatagridView dargestellt, die Spalte IDPerson ist dabei einer DataGridViewComboBoxColumn zugeordnet. Deren Datasource ist die Bindingsource der Tabelle Person mit dem DisplayMember Name.
    Sortieren des DGV's funktioniert über MouseClick auf die jeweiligen Spaltenköpfe, soweit, sogut.
    Bie Klick auf den Spaltenkopf IDPerson erfolgt auch die Sortierung, die sich natürlich an den numerischen Werten innerhalb der Spalte orientiert, und nicht an den durch die ComoboBoxColumn übersetzten Anzeigetexte.

    Ich möchte nun aber eben die Sortierung nach den Anzeigetexten erreichen, und steh' auf dem Schlauch.
    Bin für jede Anregung dankbar.
    Du kannst doch die Spalte angeben nach welcher wie sortiert werden soll. Die SortMode-Property der Spalte NIX habe ich auf NotSortable gestellt.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    3. For i = 0 To 10
    4. Dim row = DirectCast(DirectCast(PersonBindingSource.AddNew(), DataRowView).Row, DataSet1.PersonRow)
    5. row.Name = i.ToString
    6. row.NIX = (i * i).ToString
    7. Next
    8. End Sub
    9. Private Sub DataGridView1_ColumnHeaderMouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick
    10. If DataGridView1.Columns(e.ColumnIndex).Name.Equals("NIXDataGridViewTextBoxColumn") Then
    11. PersonBindingSource.Sort = "Name"
    12. End If
    13. End Sub
    14. End Class
    And i think to myself... what a wonderfuL World!
    Aber es geht doch garnicht um das Sortieren der Tabelle Person, es geht um das Sortieren der Tabelle Material, und zwar nach der Spalte IDPerson. Und in dieser Spalte nicht nach den dahinterliegenden Int32-Werten, sondern nach den Namen der Person, die sie repräsentieren.
    Oder steh' ich noch mehr auf dem Schlauch, und verstehe nicht, was Du mir sagen willst?

    Der Mechanismus zum Abfangen des MouseClicks ist natürlich klar. Es geht mir um die Sortierfunktionalität.
    Nun, eine Lösung wäre eine berechnete Spalte in der Tabelle Material mir der Expression Parent.Name.
    Dann liegen ja in dieser neuen Spalte die Namen als Text vor, und können entsprechend sortiert .werden.
    Der Nachteil ist, das diese neue Spalte auch in der dahinterliegenden Datenbank (in diesem Fall XML) persistiert werden, und das Datenvolumen nicht unerheblich aufblähen.
    Macht sich dann schon bei Ladezeiten negativ bemerkbar.
    Die Lösung mit der berechneten Spalte scheint ja wirklich die einzige Lösung zu sein. Wie gesagt, die berechneten daten werden mit perisistiert. Bei meinen Tests auf Basis von 10.000 Datensätzen hat das Laden des Datasets aus XML-Daten dann 12,5% länger gedauert (Daten liegen auf SSD), die Datei selbst ist um 26,5% grösser. Wie gesagt, bei dem einfachen Test-Beispiel.
    Muss mal schaun, wie sich das dann zur Laufzeit mit echten Daten bei ebenfalls ca. 10.000 Datensätzen macht.
    Jedenfalls vielen Dank für Eure Unterstützung.
    Never ever give up. Hab' doch noch eine Lösung gefunden:

    VB.NET-Quellcode

    1. Private Sub MaterialDataGridView_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles MaterialDataGridView.ColumnHeaderMouseClick
    2. If e.ColumnIndex = Me.IDPersonComboBoxColumn.Index Then
    3. DoTheSort()
    4. End If
    5. End Sub
    6. Private SortDirection As SortOrder = SortOrder.None
    7. Sub DoTheSort()
    8. If Me.TestDataSet.Material.Rows.Count > 0 Then
    9. Dim x As Object = Nothing
    10. Select Case SortDirection
    11. Case SortOrder.None
    12. SortDirection = SortOrder.Ascending
    13. x = Me.TestDataSet.Material.OrderBy(Function(p) p.PersonRow.Name).CopyToDataTable
    14. Case SortOrder.Ascending
    15. SortDirection = SortOrder.Descending
    16. x = Me.TestDataSet.Material.OrderByDescending(Function(p) p.PersonRow.Name).CopyToDataTable
    17. Case SortOrder.Descending
    18. SortDirection = SortOrder.None
    19. x = Me.TestDataSet.Material.OrderByDescending(Function(p) p.ID).CopyToDataTable
    20. End Select
    21. Me.TestDataSet.Material.Clear()
    22. Me.TestDataSet.Material.Merge(x)
    23. Me.TestDataSet.AcceptChanges()
    24. End If
    25. End Sub

    Ich füge ein kleines Projekt mit Testdaten bei, für die, die's interessiert.
    Dateien
    Coole Lösung - bin begeistert :thumbsup: !
    Insbesondere weil ich hab nachgeguckt, und diese quasi brutale Umverwurstelung der Tabelle endet ganz sauber, und beeinflusst nichtmal den Rowstate der betroffenen DataRows (Das AcceptChanges() zum Ende also gottseidank entbehrlich)!

    Nur ein klein Mecker: Du proggst Strict Off - (zum Kuckuck!, wie is dat nu wieder passiert?) - mit entsprechenden Schlumbadeleien.
    Ach - und x sollteste noch disposen - das ist ja ein echt fetter Batzen dann im Speicher.

    Und magste einen Tippvorschlag davon machen?
    Wir zwei beide sind sicherlich nicht die einzigen, denen die Sortier-Widerspenstigkeit von ComboboxColumns immer auffn S... ging. ;)

    ErfinderDesRades schrieb:

    ... und beeinflusst nichtmal den Rowstate der betroffenen DataRows (

    Danke für den Hinweis. Das ist richtig für den Merge-Prozess, der hinterlässt all rows mit Rowstate.Unchanged.
    AAABER:
    Das vorhergehende Datatable.Clear löscht natürlich alle bis dahin erfolgten Veränderungen. Mir fällt nix ein, wie das über den Merge-Prozess gerettet werden kann.

    Und Strict-Off:
    Wegduck und renn. Peinlich.
    Nach Neuinstallation von VS2015 geschlampt und Einstellungen nicht angepasst. Danke, Microsoft.

    Mit dem Tippvorschlag = Ebenfalls gute Idee, ist in Arbeit.

    //Edit:
    Ist heute Mittag abgesandt, muss von der Moderation freigeschaltet werden.

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