Ich habe eine folgende Klasse:
[DataContract]
public class Pair<TKey, TValue> : INotifyPropertyChanged, IDisposable
{
public Pair(TKey key, TValue value)
{
Key = key;
Value = value;
}
#region Properties
[DataMember]
public TKey Key
{
get
{ return m_key; }
set
{
m_key = value;
OnPropertyChanged("Key");
}
}
[DataMember]
public TValue Value
{
get { return m_value; }
set
{
m_value = value;
OnPropertyChanged("Value");
}
}
#endregion
#region Fields
private TKey m_key;
private TValue m_value;
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{ }
#endregion
}
Was ich in eine ObservableCollection aufgenommen habe:
ObservableCollection<Pair<ushort, string>> my_collection =
new ObservableCollection<Pair<ushort, string>>();
my_collection.Add(new Pair(7, "aaa"));
my_collection.Add(new Pair(3, "xey"));
my_collection.Add(new Pair(6, "fty"));
F: Wie sortiere ich es nach Schlüssel?
Antworten:
Das Sortieren eines beobachtbaren Objekts und das Zurückgeben des gleichen sortierten Objekts kann mithilfe einer Erweiterungsmethode erfolgen. Achten Sie bei größeren Sammlungen auf die Anzahl der geänderten Sammlungsbenachrichtigungen, z
Verwendung: Probe mit einem Beobachter (verwendet eine Personenklasse, um es einfach zu halten)
Ausgabe von oben:
entfernt Katy im Alter von 51 Jahren bei Index 0
hinzugefügt Katy im Alter von 51 Jahren bei Index 8
entfernt Mary im Alter von 41 Jahren bei Index 3
hinzugefügt Mary im Alter von 41 Jahren bei Index 7
entfernt Jane im Alter von 20 Jahren bei Index 3
hinzugefügt Jane im Alter von 20 Jahren bei Index 5
entfernt Jim im Alter von 39 Jahren bei Index 3
hinzugefügt Jim im Alter von 39 bei Index 6
Jane im Alter von 20 bei Index 4 entfernt
hinzugefügt Jane im Alter von 20 bei Index 5
Die Person-Klasse implementiert sowohl IComparable als auch IEquatable. Letzteres wird verwendet, um die Änderungen an der Sammlung zu minimieren und die Anzahl der ausgelösten Änderungsbenachrichtigungen zu verringern
Um eine ObservableCollection zurückzugeben, rufen Sie .ToObservableCollection auf * sortedOC * auf, indem Sie z. B. [diese Implementierung] [1] verwenden.
**** orig Antwort - dies erstellt eine neue Sammlung **** Sie können linq verwenden, wie die folgende doSort-Methode zeigt. Ein schneller Code-Ausschnitt: Erzeugt
3: xey 6: fty 7: aaa
Alternativ können Sie eine Erweiterungsmethode für die Sammlung selbst verwenden
quelle
ObservableCollection
, sondern eine neue Kollektion erstellt.BinarySearch
anstelle von verwendet wirdIndexOf
.Diese einfache Erweiterung hat bei mir wunderbar funktioniert. Ich musste nur sicherstellen, dass das so
MyObject
warIComparable
. Wenn die Sortiermethode für die beobachtbare Sammlung von aufgerufen wird,MyObjects
wird dieCompareTo
Methode onMyObject
aufgerufen, die meine logische Sortiermethode aufruft. Es hat zwar nicht alle Schnickschnack der restlichen Antworten, die hier veröffentlicht wurden, aber es ist genau das, was ich brauchte.quelle
return Utils.LogicalStringCompare(a.Title, b.Title);
anstelle von verwendenreturn string.Compare(a.Title, b.Title);
? @NeilWIch habe einen relevanten Blogeintrag gefunden, der eine bessere Antwort bietet als die hier:
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
AKTUALISIEREN
Die ObservableSortedList , auf die @romkyns in den Kommentaren hinweist, behält automatisch die Sortierreihenfolge bei.
Beachten Sie jedoch auch die Bemerkung
quelle
Sie können diese einfache Methode verwenden:
Sie können so sortieren:
Weitere Details: http://jaider.net/2011-05-04/sort-a-observablecollection/
quelle
ObservableCollection
Dropdown-Liste an ItemSource gebunden und sehen die Sammlung überhaupt nicht. Auch dieser Vorgang des Löschens und Auffüllens ist ultraschnell ... der "langsame" kann die Sorte sein, die bereits optimiert ist. Schließlich können Sie diesen Code ändern , um Ihre Bewegungsverfahren zu implementieren, mit dersortedlist
undsource
der Rest ist einfach.Move
Ereignisse aus, auch dies nur für die wirklich bewegten.WPF bietet Live-Sortierung mit der
ListCollectionView
Klasse ...Sobald diese Initialisierung abgeschlossen ist, gibt es nichts mehr zu tun. Der Vorteil gegenüber einer passiven Sortierung besteht darin, dass die ListCollectionView das gesamte schwere Heben auf eine Weise ausführt, die für den Entwickler transparent ist. Neue Artikel werden automatisch in der richtigen Sortierreihenfolge platziert. Jede Klasse, die von abgeleitet ist
IComparer
von T abgeleitet ist, ist für die benutzerdefinierte Sortiereigenschaft geeignet.In ListCollectionView finden Sie die Dokumentation und andere Funktionen.
quelle
Ich mochte den Ansatz der Blasensortierungserweiterungsmethode in "Richies" Blog oben, aber ich möchte nicht unbedingt nur das gesamte Objekt vergleichen. Ich möchte häufiger nach einer bestimmten Eigenschaft des Objekts sortieren. Deshalb habe ich es so geändert, dass es wie KeyBy einen Schlüssel-Selektor akzeptiert, sodass Sie auswählen können, nach welcher Eigenschaft sortiert werden soll:
Was Sie genauso aufrufen würden wie OrderBy, außer dass die vorhandene Instanz Ihrer ObservableCollection sortiert wird, anstatt eine neue Sammlung zurückzugeben:
quelle
OrderBy
durchzuführen , sondern diese extern mit zu sortieren und dann einen Vergleich durchzuführen, um die tatsächliche Änderung herauszufinden.Die Antwort von @ NielW ist der richtige Weg für eine echte Sortierung vor Ort. Ich wollte eine leicht veränderte Lösung hinzufügen, mit der Sie umgehen müssen
IComparable
:Jetzt können Sie es wie die meisten LINQ-Methoden aufrufen:
quelle
if(!Ascending) sorted.Reverse();
kurz vor demfor
: D (und keine Notwendigkeit, -further- Sorge über das Gedächtnis, das Reverse - Verfahren keine neuen Objekte schafft, ist es an Ort und Stelle umgekehrt)Ich möchte NeilWs Antwort ergänzen . Einfügen einer Methode, die der Reihenfolge ähnelt. Fügen Sie diese Methode als Erweiterung hinzu:
Und verwenden Sie wie:
quelle
In einer Variante sortieren Sie die Sammlung mithilfe eines Auswahlsortieralgorithmus . Elemente werden mithilfe der
Move
Methode an ihren Platz verschoben . Jeder Zug löst dasCollectionChanged
Ereignis mitNotifyCollectionChangedAction.Move
(und auchPropertyChanged
mit dem EigenschaftsnamenItem[]
) aus.Dieser Algorithmus hat einige nette Eigenschaften:
CollectionChanged
ausgelöste Ereignisse) ist fast immer geringer als bei anderen ähnlichen Algorithmen wie Einfügesortierung und Blasensortierung.Der Algorithmus ist recht einfach. Die Sammlung wird iteriert, um das kleinste Element zu finden, das dann an den Anfang der Sammlung verschoben wird. Der Vorgang wird ab dem zweiten Element usw. wiederholt, bis alle Elemente an ihren Platz verschoben wurden. Der Algorithmus ist nicht besonders effizient, aber für alles, was Sie in einer Benutzeroberfläche anzeigen möchten, sollte es keine Rolle spielen. In Bezug auf die Anzahl der Verschiebevorgänge ist es jedoch ziemlich effizient.
Hier ist eine Erweiterungsmethode, die der Einfachheit halber die Implementierung der Elemente erfordert
IComparable<T>
. Andere Optionen verwenden einIComparer<T>
oder einFunc<T, T, Int32>
.Beim Sortieren einer Sammlung müssen Sie lediglich die Erweiterungsmethode aufrufen:
quelle
T
, um die Elemente in der Auflistung sortieren zu können. Das Sortieren beinhaltet das Konzept von größer und kleiner als und nur Sie können definieren, wieProfileObject
bestellt wird. So verwenden Sie die Erweiterung Methode , die Sie implementieren müssenIComparable<ProfileObject>
aufProfileObject
. Andere Alternativen sind wie angegeben unter Angabe von aIComparer<ProfileObject>
oder aFunc<ProfileObject, ProfileObject, int>
und ändern den Sortiercode entsprechend.Um die Erweiterungsmethode für die Antwort xr280xr ein wenig zu verbessern, habe ich einen optionalen bool-Parameter hinzugefügt, um festzustellen, ob die Sortierung absteigend ist oder nicht. Ich habe auch den Vorschlag von Carlos P in den Kommentar zu dieser Antwort aufgenommen. Siehe unten.
quelle
Müssen Sie Ihre Sammlung jederzeit sortieren? Müssen die Paare beim Abrufen immer sortiert sein oder nur einige Male (möglicherweise nur zum Präsentieren)? Wie groß soll Ihre Sammlung sein? Es gibt viele Faktoren, die Ihnen bei der Entscheidung für die Hexenmethode helfen können.
Wenn Sie möchten, dass die Sammlung jederzeit sortiert wird, auch wenn Sie Elemente einfügen oder löschen und die
SortedObservableCollection
Einfügegeschwindigkeit kein Problem darstellt, sollten Sie möglicherweise eine Art von @Gerrie Schenck implementieren oder diese Implementierung überprüfen .Wenn Sie Ihre Sammlung nur für ein paar Mal sortieren müssen, verwenden Sie:
Das Sortieren der Sammlung wird einige Zeit in Anspruch nehmen, ist jedoch möglicherweise die beste Lösung, je nachdem, was Sie damit tun.
quelle
Meine aktuelle Antwort hat bereits die meisten Stimmen, aber ich habe einen besseren und moderneren Weg gefunden, dies zu tun.
quelle
Erstellen Sie eine neue Klasse
SortedObservableCollection
, leiten Sie sie abObservableCollection
und implementieren Sie sieIComparable<Pair<ushort, string>>
.quelle
Eine Möglichkeit wäre, es in eine Liste zu konvertieren und dann Sort () aufzurufen, um einen Vergleichsdelegierten bereitzustellen. Etwas wie:-
(ungetestet)
quelle
Ich denke, das ist die eleganteste Lösung:
http://www.xamlplayground.org/post/2009/07/18/Use-CollectionViewSource-effectively-in-MVVM-applications.aspx
quelle
Was zum Teufel, ich werde auch eine schnell zusammengepflasterte Antwort einwerfen ... es sieht ein bisschen aus wie einige andere Implementierungen hier, aber ich werde es trotzdem hinzufügen:
(kaum getestet, hoffentlich schäme ich mich nicht)
Lassen Sie uns zuerst einige Ziele angeben (meine Annahmen):
1) Muss
ObservableCollection<T>
an Ort und Stelle sortiert werden , um Benachrichtigungen usw. aufrechtzuerhalten.2) Darf nicht schrecklich ineffizient sein (dh etwas nah an Standard „gut“ Sortiereffizienz)
quelle
Keine dieser Antworten hat in meinem Fall funktioniert. Entweder weil es die Bindung vermasselt oder so viel zusätzliche Codierung erfordert, dass es eine Art Albtraum ist, oder weil die Antwort einfach kaputt ist. Also, hier ist noch eine einfachere Antwort, dachte ich. Es ist viel weniger Code und es bleibt dieselbe beobachtbare Sammlung mit einer zusätzlichen Methode vom Typ this.sort. Lassen Sie mich wissen, ob es einen Grund gibt, warum ich es nicht so machen sollte (Effizienz usw.)?
... wo ScoutItem meine öffentliche Klasse ist. Schien einfach viel einfacher. Zusätzlicher Vorteil: Es funktioniert tatsächlich und spielt nicht mit Bindungen oder gibt eine neue Sammlung usw. zurück.
quelle
Okay, da ich Probleme hatte, ObservableSortedList mit XAML zum Laufen zu bringen , habe ich SortingObservableCollection erstellt . Es erbt von ObservableCollection, funktioniert also mit XAML und ich habe es auf 98% Codeabdeckung getestet. Ich habe es in meinen eigenen Apps verwendet, aber ich werde nicht versprechen, dass es fehlerfrei ist. Fühlen Sie sich frei, einen Beitrag zu leisten. Hier ist die Verwendung des Beispielcodes:
Da es sich um eine PCL handelt, sollte sie mit Windows Store, Windows Phone und .NET 4.5.1 funktionieren.
quelle
new
alle diese Methoden verwenden. Wenn jemand eine allgemeinere Instanz hat, werden diese Methoden nicht aufgerufen. Stattdessenoverride
jede überschreibbare Methode und ändern Sie sie nach Bedarf oder Fallback aufbase.Method(...)
. Sie müssen sich zum Beispiel nicht einmal darum kümmern,.Add
da dies intern verwendet.InsertItem
wird. Wenn.InsertItem
es also überschrieben und angepasst wird,.Add
wird die Bestellung nicht beeinträchtigt.Folgendes mache ich mit OC-Erweiterungen:
quelle
Das hat bei mir funktioniert, ich habe es vor langer Zeit irgendwo gefunden.
Verwendung:
quelle
Ich musste in der Lage sein, nach mehreren Dingen zu sortieren, nicht nur nach einem. Diese Antwort basiert auf einigen anderen Antworten, ermöglicht jedoch eine komplexere Sortierung.
Wenn Sie es verwenden, übergeben Sie eine Reihe von OrderBy / ThenBy-Aufrufen. So was:
quelle
Ich habe viel aus den anderen Lösungen gelernt, aber ich habe ein paar Probleme gefunden. Erstens hängen einige von IndexOf ab, was bei großen Listen eher langsam ist. Zweitens hatte meine ObservableCollection EF-Entitäten und die Verwendung von Entfernen schien einige der Fremdschlüsseleigenschaften zu beschädigen. Vielleicht mache ich etwas falsch.
Unabhängig davon kann stattdessen A Move zum Entfernen / Einfügen verwendet werden. Dies führt jedoch zu einigen Problemen bei der Leistungskorrektur.
Um das Leistungsproblem zu beheben, erstelle ich ein Wörterbuch mit den sortierten IndexOf-Werten. Verwenden Sie einen Swap, der mit zwei Zügen implementiert ist, anstatt eines, wie in anderen Lösungen implementiert, um das Wörterbuch auf dem neuesten Stand zu halten und die Entitätseigenschaften beizubehalten.
Durch eine einzelne Verschiebung werden die Indizes der Elemente zwischen den Positionen verschoben, wodurch das IndexOf-Wörterbuch ungültig wird. Durch Hinzufügen eines zweiten Schrittes zum Implementieren eines Austauschs werden Standorte wiederhergestellt.
quelle
quelle