{"id":224,"date":"2006-04-18T21:01:07","date_gmt":"2006-04-18T19:01:07","guid":{"rendered":"http:\/\/www.puls200.de\/?p=224"},"modified":"2006-04-18T21:01:41","modified_gmt":"2006-04-18T19:01:41","slug":"sortierbare-spalten","status":"publish","type":"post","link":"https:\/\/www.puls200.de\/?p=224","title":{"rendered":"Sortierbare Spalten"},"content":{"rendered":"<p>Diesmal ein eher technischer Eintrag, dessen Zweck eher eigene Gedankenst\u00fctze als \u00f6ffentliche Erheiterung ist. Hoffe ich zumindest.<\/p>\n<p>Im .NET Framework 2.0 gibt es zus\u00e4tzlich zum bekannten DataGrid Steuerelement das neue DataGridView. Dessen F\u00e4higkeiten wurden gegen\u00fcber dem Vorg\u00e4nger stark erweitert, so da\u00df es inzwischen nur noch Sekunden dauert, um eine Datenquelle \u00fcber ADO oder eine eigene Implementierung an die Tabelle anzuschlie\u00dfen. Das Ding bringt bereits nette F\u00e4higkeiten mit, z.B. die Spalten umzuordnen. Die Spalten allerdings (durch einen Klick auf den Spaltenkopf) automatisch umzusortieren ist leider nicht so einfach, wie es zun\u00e4chst aussieht. Das Sortieren der Datenquelle funktioniert nur dann problemlos, wenn ein Datagrid bzw. ein Dataview angebunden ist. Kommen die Daten direkt aus der Datenbank ist das auch kein Problem. Hat man jedoch die anzuzeigenden Objekte woanders her, z.B. aus einer Liste, funktioniert das leider nicht mehr. Die Liste wei\u00df nicht, nach welchen Kriterien sie sortieren soll. Die L\u00f6sung besteht darin, eine eigene Listenimplementierung einzuf\u00fchren, die von der urspr\u00fcnglichen Liste erbt und zus\u00e4tzlich <em>IBindingList<\/em> implementiert.<br \/>\n<code><br \/>\npublic void ApplySort(PropertyDescriptor property, ListSortDirection direction)<br \/>\n        {<br \/>\n            Trace.WriteLine(string.Format(\"sorting column {0}\",property.DisplayName));<br \/>\n            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(AISShip));<br \/>\n            this.sortProperty = properties.Find(property.DisplayName, true);<br \/>\n            this.Sort(this.Comparison);<br \/>\n            this.OnListChanged(resetEvent);<br \/>\n        }<br \/>\n<\/code><br \/>\nDiese Methode ist ein Teil der Implementierung von <em>IBindingList<\/em>. Sie wird beim Sortieren der Liste implizit (vom DataGridView durch ein callback) aufgerufen. Das spaltenrelevante Sortieren habe ich so gel\u00f6st, da\u00df die entsprechende Spalte lokal gespeichert wird und die Suchfunktion mit einem Vergleichs-Delegaten aufgerufen wird. Das wirkt etwas ungew\u00f6hnlich, es ist auch eine Neuerung in .NET 2.0.<br \/>\nDie eigentliche Vergleichsfunktion sieht etwas lahmarschig aus, man h\u00e4tte hier sicher noch eleganter mit Reflection arbeiten k\u00f6nnen (wenn auch weniger performant):<br \/>\n<code><br \/>\nprotected int Comparison(AISShip a, AISShip b)<br \/>\n        {<br \/>\n            if (this.sortProperty.Name.Equals(\"Timestamp\"))<br \/>\n                return a.Timestamp.CompareTo(b.Timestamp);<br \/>\n            if (this.sortProperty.Name.Equals(\"Name\"))<br \/>\n                return a.Name.CompareTo(b.Name);<br \/>\n            if (this.sortProperty.Name.Equals(\"Callsign\"))<br \/>\n                return a.Callsign.CompareTo(b.Callsign);<br \/>\n            if (this.sortProperty.Name.Equals(\"IMO\"))<br \/>\n                return a.IMO.CompareTo(b.IMO);<br \/>\n            \/\/ usw.<br \/>\n            return 0;<br \/>\n        }<br \/>\n<\/code><br \/>\nEine weitere Verbesserung kann man noch einbauen, wenn man sich beim Suchen au\u00dferdem die letzte Sortierrichtung merkt und diese dann umdreht, falls sich die Spalte nicht ge\u00e4ndert hat. Damit erreicht man dann das typische Verhalten, da\u00df der Benutzer aus dem Windows Explorer her kennt.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>C#, DataGridView, IBindingList, sorting, column headers, .NET 2.0 <a href=\"https:\/\/www.puls200.de\/?p=224\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0},"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/www.puls200.de\/index.php?rest_route=\/wp\/v2\/posts\/224"}],"collection":[{"href":"https:\/\/www.puls200.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.puls200.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.puls200.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.puls200.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=224"}],"version-history":[{"count":0,"href":"https:\/\/www.puls200.de\/index.php?rest_route=\/wp\/v2\/posts\/224\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.puls200.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.puls200.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.puls200.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}