Laden...

Listview Spalten sortieren

Erstellt von mkolb vor 2 Jahren Letzter Beitrag vor 2 Jahren 673 Views
M
mkolb Themenstarter:in
52 Beiträge seit 2017
vor 2 Jahren
Listview Spalten sortieren

Hallo,
ich habe eine Listview im im DETAIL-Style möchte ich die Werte nach Spaltenklick sortieren lassen.

Habe dazu diesen Code gefunden, der vielversprechend aussieht:

C# - ListView Spalten sortieren

Allerdings erhalte ich hier in der letzten Zeile eine Fehlermeldung:

Fehlermeldung:
CS1955 Der nicht aufrufbare Member "ColumnSorter" kann nicht wie eine Methode verwendet werden.


                listView1.Sort();
                // ListViewItemSorter property neu setzen
                this.listView1.ListViewItemSorter = ColumnSorter(e.Column, listView1.Sorting);

Die Klasse ist gem. dem Snippet aus dem Link erstellt.
Hat jemand eine Idee, was falsch ist, wie es korrekt ist ?

Tschau
Martin

Klasse:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Listview_Sorter
{
    public class ColumnSorter : IComparer
    {
        //https://dotnet-snippets.de/snippet/listview-spalten-sortieren/1158
        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;
        }
    }
}

16.834 Beiträge seit 2008
vor 2 Jahren

Siehe Dokumentation https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.listview.listviewitemsorter mit Beispielcode, wie man einen Comparer richtig zuweist:


           // Set the ListViewItemSorter property to a new ListViewItemComparer 
            // object. Setting this property immediately sorts the 
            // ListView using the ListViewItemComparer object.
            this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column);

Du wilst schließlich die Instanz haben und nicht den Rückgabewert. Das Snippet ist an der Stelle wohl einfach falsch.

An für sich ist das ohnehin eh suboptimal:
Man sollte immer die Inhalte sortieren, und keine UI Elemente - nur leider ist die ListView eine sehr veraltete Komponente, die keine Datenbindung zulässt.
Gibt aber zahlreiche Erweiterungen im Open Source Bereich, die sowas zulassen.

Fazit: Snippets nicht blind kopieren, sondern versuchen zu verstehen.

M
mkolb Themenstarter:in
52 Beiträge seit 2017
vor 2 Jahren

Habe gerade eine Lösung gefunden:
Da muß ein "new" rein ...


this.listView1.ListViewItemSorter = [b]new[/b] ColumnSorter(e.Column, listView1.Sorting);

  1. Problem danach:

Hier werden Werte nach String verglichen:


                // Werte als string vergleichen
                result = String.Compare(((ListViewItem)x).SubItems[col].Text,
                            ((ListViewItem)y).SubItems[col].Text);

Ich möchte aber nach Zahlen mit Komma (also Double) aus der Tabelle vergleichen.
Wie mache ich hier einen Vergleich ?

Tschau
Martin

16.834 Beiträge seit 2008
vor 2 Jahren

Wie mache ich hier einen Vergleich ?

Dann musst das halt umschreiben, wenn Du andere Typen hast. Das wird Dir nich so zufliegen.
Wie das mit Double geht siehst in der Doku: https://docs.microsoft.com/de-de/dotnet/api/system.double.parse?view=net-6.0 bzw. mal durchlesen, wie der Comparer funktioniert (Hint: dem ist egal, welche Typen Du hast, weil sich die Entscheidung immer nach int richtet).
Nen bisschen musst die Grundlagen schon selbst lernen 😉

M
mkolb Themenstarter:in
52 Beiträge seit 2017
vor 2 Jahren

Hallo Abt,
die Erkennung über den Typ habe ich. Allerdings geht das mit dem Compare nicht, gibt es nicht für int bzw. double. Es gibt nur CompareTo. Das klappt allerdings auch nicht.


            else if (Double.TryParse(inhalt, out TestZahl))
            {
                // Werte als string vergleichen
                result = (((ListViewItem)x).SubItems[col].Text.CompareTo(((ListViewItem)y).SubItems[col].Text));
            }

Haste noch einen Tipp für mich ?

Tschau
Martin

M
mkolb Themenstarter:in
52 Beiträge seit 2017
vor 2 Jahren

muß es doch etwas umständlicher machen, als gedacht:


            else if (Double.TryParse(inhalt, out TestZahl))
            {
                // Werte als Double vergleichen
                double vx = double.Parse(((ListViewItem)x).SubItems[col].Text);
                double vy = double.Parse(((ListViewItem)y).SubItems[col].Text);
                result = vx.CompareTo(vy);
            }

Geht das auch eleganter ?

16.834 Beiträge seit 2008
vor 2 Jahren

Nein, weil Du schließlich double Werte miteinander vergleichen willst und keine Strings.
Du kommst bei der veralteten ListView um casten nicht drum herum.
Auch das steht übrigens mit genau dem Beispiel in der Doku (ListView.SelectedItems Eigenschaft (System.Windows.Forms)) 🙂

3.825 Beiträge seit 2006
vor 2 Jahren

Bei Datumsfeldern auch in datetime casten und dann vergleichen.

Ich würde kein TryParse benutzen. sondern in einer eigenen Tabelle oder in der Tag-Eigenschaft der Spalte den Datentyp hinterlegen.
Es können ja auch Zahlen in string Spalten stehen : Artikelnummer, Hausnummer, Postleitzahl etc.
auch funktioniert deine Routine nicht wenn in einer Zelle eine Zahl steht und in der zweiten nicht.

Obwohl listview schon sehr veraltet ist nutze ich das fleißig und klappt immer gut.

Man kann sogar ein listview so bauen dass es virtuell lädt, also bei 1 Mio. Datensätzen schon nach 1 Sekunde ein Ergebnis anzeigt (Lazy Load).

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

M
mkolb Themenstarter:in
52 Beiträge seit 2017
vor 2 Jahren

Hi,
das mit dem Datumsprüfen kann ich irgendwie abhaken, egal ob Casten oder Parse oder ähnl.
Habe Zahlenwerte, z. B. 8,1943 und diese werden als August 1943 erkannt, oder 12.5432 die als Dezember 5432 erkannt werden.
Habe es anders gelöst, in dem ich angebe, nach welcher Art eine Spalte sortiert werden soll: Text, Zahl oder Datum.
In meinen Tabellen verwende ich keinen Mischbetrieb, d. h. ich entscheide welche Art (s.v.) es ist. Eine autom. Erkennung ist irgendwann fehlerbehaftet.

Danke für die Unterstützungen.

Tschau
Martin