2 Stimmen

Wie sortiert man ListView Elemente, wenn ListView im VirtualMode ist?

Ich erkenne, dass ich die Sammlung, wo die ListView sammelt die Elemente aus sortieren müssen:
ListView listCollection = new ListView();

Aber dies scheint nicht zu funktionieren, es sei denn, die ListView als GUI-Steuerelement zum Formular hinzugefügt wird, das wiederum macht es sehr langsam, um Elemente hinzuzufügen, daher warum ich VirtualMode auf meine GUI-ListView in erster Linie verwenden müssen.

Weiß jemand, wie man dabei vorgeht, oder kann mir die richtige Richtung weisen?

3voto

bernhof Punkte 6101

Grundsätzlich müssen Sie die Sortierung auf die Datenpumpe selbst anwenden.

Ich habe eine schnelle Suche bei Google nach listenansicht sortieren virtualmode . Das erste Ergebnis war diese Seite wo das obige Zitat entnommen wurde.

Wenn es sich bei Ihrer Datenquelle beispielsweise um eine DataView handelt, wenden Sie die Sortierung auf diese anstatt auf die ListView an.

Wenn es nur um die Leistung beim Hinzufügen von Elementen geht, würde ich wie folgt vorgehen Barismus vorschlägt; verwenden Sie BeginUpdate/EndUpdate anstelle von VirtualMode.

try {
  listView1.BeginUpdate();
  // add items
}
finally {
  listView1.EndUpdate();
}

3voto

Grammarian Punkte 6539

Wenn Sie den virtuellen Modus verwenden, müssen Sie Ihre zugrunde liegende Datenquelle sortieren. Wie Sie vielleicht schon festgestellt haben, tut ListViewItemSorter nichts für virtuelle Listen.

Wenn Sie eine nicht-virtuelle Listenansicht verwenden, können Sie auch AddRange() verwenden, was wesentlich schneller ist als eine Reihe von Add() -- zusätzlich zur Verwendung von BeginUpdate/EndUpdate, die bereits beschrieben wurde.

ObjectListView (ein Open-Source-Wrapper um .NET WinForms ListView) verwendet bereits alle diese Techniken, um schnell zu sein. Es ist eine große Verbesserung gegenüber einer normalen ListView. Es unterstützt sowohl den normalen als auch den virtuellen Modus von ListViews, und macht beide viel einfacher zu benutzen. Zum Beispiel wird die Sortierung völlig automatisch durchgeführt.

3voto

Riccardo Punkte 21

Ich hatte das gleiche Problem beim Umschalten von VirtualMode True mit einem bestehenden Projekt, aber die Lösung war überraschend einfach:

Im ersten Schritt fülle ich eine Liste von ListViewItem auf, anstatt der ListView.Items Sammlung:

private List<ListViewItem> _ListViewItems;

Dann habe ich die Methode RetrieveVirtualItem implementiert

private void mLV_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    e.Item = _ListViewItems[e.ItemIndex];
}

Schließlich sortiere ich meine ListViewItem-Liste mit der gleichen Klasse, die ich vorher verwendet habe, ich musste nur die Basisklasse ändern

_ListViewItems.Sort((System.Collections.Generic.IComparer<ListViewItem>)new ListViewItemComparer(new int[] { e.Column }, mLV.Sorting));

Dies ist meine Implementierung der Klasse IComparer:

class ListViewItemComparer : System.Collections.Generic.IComparer<ListViewItem>
{
    int[] mColonne;
    private System.Windows.Forms.SortOrder order;
    public ListViewItemComparer(int[] mCols)
    {
        this.mColonne = mCols;
        this.order = System.Windows.Forms.SortOrder.Ascending;
    }

    public ListViewItemComparer(int[] mCols, System.Windows.Forms.SortOrder order)
    {
        this.mColonne = mCols;
        this.order = order;
    }

    public int Compare(ListViewItem x, ListViewItem y)
    {
        int returnVal = -1;

        foreach (int mColonna in mColonne)
        {
            double mNum1;
            double mNum2;

            String mStr1 = "";
            String mStr2 = "";

            if ((x.SubItems[mColonna].Text == "NULL") && (x.SubItems[mColonna].ForeColor == Color.Red))
            {
                mStr1 = "-1";
            }
            else
            {
                mStr1 = x.SubItems[mColonna].Text;
            }

            if ((y.SubItems[mColonna].Text == "NULL") && (y.SubItems[mColonna].ForeColor == Color.Red))
            {
                mStr2 = "-1";
            }
            else
            {
                mStr2 = y.SubItems[mColonna].Text;
            }

            if ((double.TryParse(mStr1, out mNum1) == true) && (double.TryParse(mStr2, out mNum2) == true))
            {
                if (mNum1 == mNum2)
                {
                    returnVal = 0;
                }
                else if (mNum1 > mNum2)
                {
                    returnVal = 1;
                }
                else
                {
                    returnVal = -1;
                }
            }
            else if ((double.TryParse(mStr1, out mNum1) == true) && (double.TryParse(mStr2, out mNum2) == false))
            {
                returnVal = -1;
            }
            else if ((double.TryParse(mStr1, out mNum1) == false) && (double.TryParse(mStr2, out mNum2) == true))
            {
                returnVal = 1;
            }
            else
            {
                returnVal = String.Compare(mStr1, mStr2);
            }

            if (returnVal != 0)
            {
                break;
            }
        }

        // Determine whether the sort order is descending.
        if (order == System.Windows.Forms.SortOrder.Descending)
        {
            // Invert the value returned by String.Compare.
            returnVal *= -1;
        }
        return returnVal;
    }
}

Ich hoffe, das hilft Ihnen weiter.

1voto

bmeric Punkte 1108

Haben Sie beginupdate() und endupdate() ausprobiert? Das Hinzufügen von Daten geht viel schneller, wenn Sie beginupdate/endupdate verwenden. (Wenn Sie beginupdate aufrufen, wird die Listenansicht nicht gezeichnet, bis Sie endupdate aufrufen)

listView1.BeginUpdate();
for (int i = 0; i < 20000; i++)
{
listView1.Items.Add("abdc", 1);
}
listView1.EndUpdate();

1voto

David Punkte 76

Für sehr große Listen ist die ListView im virtuellen Modus die richtige Lösung. Im nicht-virtuellen Modus scheint es, um die gesamte Liste zu zeichnen und dann Clip es an die Ansicht, während im virtuellen Modus es einfach zeichnet die in der Ansicht. In meinem Fall bestand die Liste aus 40K+ Datensätzen. Im nicht-virtuellen Modus konnte eine Aktualisierung der ListView Minuten dauern. Im virtuellen Modus erfolgte sie sofort.

Um die Liste zu sortieren, müssen Sie, wie bereits erwähnt, die zugrunde liegende Datenquelle sortieren. Das ist der einfache Teil. Sie müssen auch eine Aktualisierung der Anzeige erzwingen, die no automatisch durchgeführt. Sie können ListView.TopItem.Index verwenden, um den Index in der zugrunde liegenden Datenquelle zu finden, der der obersten Zeile der virtuellen Listenansicht vor der Sortierung entspricht. Es gibt auch einen API-Aufruf, der die Anzahl der Anzeigezeilen in der ListView zurückgibt, die Sie als C#-Funktion implementieren können, wie hier:

public const Int32 LVM_GETCOUNTPERPAGE = 0x1040;

public static int GetListViewRows( ListView xoView ) 
{
   return (int)WindowsMessage.SendMessage( xoView.Handle, LVM_GETCOUNTPERPAGE, 0, 0 );
}

So können Sie den Bereich berechnen, den Sie aktualisieren müssen. Bleibt nur noch die Frage zu klären, wie Sie die bestehende Anzeige mit der neuen Anzeige in Einklang bringen nach Die Daten wurden sortiert. Wenn Sie dasselbe Datenelement in der obersten Zeile belassen wollen, müssen Sie einen Mechanismus einrichten, der seinen neuen Index in der neu sortierten Liste findet, damit Sie es an der obersten Position ersetzen können - etwas, das im Wesentlichen einer SQL-IDENTITY entspricht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X