Feedback

C# - ListView Spalten sortieren

Veröffentlicht von am 6/16/2009
(2 Bewertungen)
Um die Spalten einer ListView sortieren zu können muss man eine Klasse schreiben, die das Interface IComparer implementiert.
public class ColumnSorter : IComparer
{
    private int col;
    private SortOrder order;
    public ColumnSorter()
    {
        col = 0;
        order = SortOrder.Ascending;
    }
    public ColumnSorter(int column, SortOrder order)
    {
        col = column;
        this.order = order;
    }
    
    public int Compare(object x, object y)
    {
        int result;
        
        try
        {
            // versuchen die 2 Werte als Datum zu vergleichen
            System.DateTime first =
                    DateTime.Parse(((ListViewItem)x).SubItems[col].Text);
            System.DateTime second =
                    DateTime.Parse(((ListViewItem)y).SubItems[col].Text);
            // Vergleichen der 2 Werte
            result = DateTime.Compare(first, second);
        }
        // Wenn der Vergleich nicht als Datum geht als string vergleichen
        catch
        {
            // Werte als string vergleichen
            result = String.Compare(((ListViewItem)x).SubItems[col].Text,
                        ((ListViewItem)y).SubItems[col].Text);
        }
        
        if (order == SortOrder.Descending)
        {
            //invertieren da desc
            result = result * -1;
        }
        return result;
    }
}

Im Programm reagiert man auf das ColumnClick event der ListView
//globale Variable um sich zu merken welche Spalte zuletzt benutzt wurde
private int lastsortColumn =-1; 

private void myListView_ColumnClick(object sender, ColumnClickEventArgs e)
{
    try
    {
        Cursor = Cursors.WaitCursor;
       
        // Behandlung wenn Spalte gerade sortiert wurde
        if (e.Column != lastsortColumn)
        {
            //Spalte merken
            lastsortColumn = e.Column;
            myListView.Sorting = SortOrder.Ascending;
        }
        else
        {
            //da Spalte zuvor sortiert wurde, in umgekehrter Reihenfolge sortieren
            if (myListView.Sorting == SortOrder.Ascending)
            {
                myListView.Sorting = SortOrder.Descending;
            }
            else
            {
                myListView.Sorting = SortOrder.Ascending;
            }
        }
        
        myListView.Sort();
        // ListViewItemSorter property neu setzen
        this.myListView.ListViewItemSorter = ColumnSorter(e.Column,myListView.Sorting);

    }
    catch (Exception ex)
    {
        //Fehlerbehandlung
    }
    finally
    {
        Cursor = Cursors.Default;
    }
}


Abgelegt unter ListView, Sortieren, Spalten, nach Datum, .

4 Kommentare zum Snippet

Rainer Hilmer schrieb am 6/16/2009:
So wie ich das beim Überfliegen gesehen habe, wird entweder nach Datum oder nach String verglichen - und das auch noch über einen Try/Catch-Block. Wäre es nicht eleganter wenn die Compare-Methode zwei Objekte vom Typ IComparable entgegennimmt? Try/Catch ist eigentlich nicht für solche Aufgaben gedacht und hier eine Krücke.
Rainer Hilmer schrieb am 6/16/2009:
Siehe auch hier:
http://support.microsoft.com/kb/319401
TBBsolutions schrieb am 6/18/2009:
ich gebe zu es ist keine elegante Lösung, es erst als Datum zu probieren, aber wenn man die im Methode im Artikel probiert
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text,listviewY.SubItems[ColumnToSort].Text);

werden die Felder nur als Text verglichen, und somit ist die Sortierung von Datums Spalten falsch.
Das Ganze wird durch das Try auch langsamer, besser wäre es sich Spalten, bei denen es nicht geht, da kein Datum, zu merken und es dann nicht mehr zu probieren, wobei es dann passieren kann, wenn einmal kein Wert in einer Zeile steht, die Sortierung auch nicht mehr richtig durchgeführt wird.
Marcus schrieb am 12/14/2010:
Hallo,

man könnte vor dem Vergleich den Datentyp mit "is" prüfen.

Beispiel:

if(x is datetime){}


oder die Methode "TryParse" verwendet.

Beispiel:

if(datetime.TryParse(((ListViewItem)x).SubItems[col].Text, out first)) {}
 

Logge dich ein, um hier zu kommentieren!