Was verursacht eine WPF-ListCollectionView, die die benutzerdefinierte Sortierung verwendet, um ihre Elemente neu zu sortieren?

8

Betrachten Sie diesen Code (geben Sie Namen ein, die zu Beispielzwecken generisch sind):

%Vor%

Wenn ich CustomSort einstelle, wird die Sammlung wie erwartet sortiert.

Allerdings müssen die Daten zur Laufzeit als Reaktion auf die Änderung der Eigenschaften in Item neu sortiert werden. Die Klasse Item wird von INotifyPropertyChanged abgeleitet und ich weiß, dass die Eigenschaft korrekt ausgelöst wird, da meine Datenvorlage die Werte auf dem Bildschirm aktualisiert, nur die Sortierlogik wird nicht aufgerufen.

Ich habe auch versucht, INotifyPropertyChanged.PropertyChanged anzuwerfen, indem ich eine leere Zeichenfolge übergebe, um zu sehen, ob eine generische Benachrichtigung dazu führen würde, dass die Sortierung ausgelöst wird. Keine Bananen.

BEARBEITEN Als Antwort auf Kents Vorschlag wollte ich darauf hinweisen, dass das Sortieren der Elemente das gleiche Ergebnis hat, nämlich dass die Sammlung einmal sortiert, aber nicht neu sortieren, wenn sich die Daten ändern:

%Vor%     
Drew Noakes 02.03.2009, 10:17
quelle

4 Antworten

7

Ich fand diesen Artikel von Dr. WPF Das beginnt mit einer Antwort auf meine Frage, dann geht es weiter, um den Leistungseinfluss von Refresh zu diskutieren. Einige wichtige Auszüge:

  

Leider führt die Refresh () Methode zu einer vollständigen Neugenerierung der Ansicht. Wenn eine Aktualisierung () in der Ansicht auftritt, löst sie eine CollectionChanged-Benachrichtigung aus und stellt die Aktion als "Zurücksetzen" bereit. Der ItemContainerGenerator für die ListBox empfängt diese Benachrichtigung und reagiert, indem er alle vorhandenen Grafiken für die Elemente verwirft. Es regeneriert dann vollständig neue Objektcontainer und Visuals.

Er beschreibt dann einen Hacky-Workaround, der die Leistung verbessert. Anstatt Refresh aufzurufen, entfernen Sie das Element, ändern Sie es und fügen Sie es erneut hinzu.

Ich hätte es für möglich gehalten, dass die Listenansicht ein Element verfolgen könnte, das sich ändert und weiß, dass es dieses Element innerhalb der Ansicht neu positionieren muss.

Ein neuer Ansatz wurde in .NET 3.5 eingeführt SP1 mit der Schnittstelle IEditableObject , die eine Transaktionsbearbeitung über Datenbindungen zur Vorlage mit den Methoden BeginEdit() , CancelEdit() und EndEdit() bietet. Lesen Sie den Artikel für weitere Informationen.

BEARBEITEN Als user346528 weist darauf hin , IEditableObject war in 3.5SP1 nicht neu. Es sieht tatsächlich so aus, als wäre es im Framework seit 1.0 .

    
Drew Noakes 02.03.2009, 11:51
quelle
6

Wie die angenommene Antwort mich anweist, bin ich in der Lage, die Einzelpositionsreposition mit Code zu erzwingen

%Vor%

Dabei ist changedItem das Ansichtsmodell (das Element in der ItemsSource -Auflistung).

Auf diese Weise brauchen Sie Ihre Elemente nicht, um Schnittstellen wie IEditableObject zu implementieren (was meiner Meinung nach in einigen Fällen sehr komplex und schwer zu implementieren ist).

    
Gman 05.04.2013 11:09
quelle
1

Da Sie die benutzerdefinierte Sortierung verwenden, gibt es für ListCollectionView keine Möglichkeit zu wissen, welche Kriterien eine Aktualisierung auslösen sollten. Daher müssen Sie Refresh() für die Sammlungsansicht selbst aufrufen.

    
Kent Boogaart 02.03.2009 10:36
quelle
1

Stoßen Sie einen alten Post an, erstellen Sie jedoch eine neue Auflistungsklasse, die von ListViewCollection und Overrides OnPropertyChanged erbt (für eine IBindingList enthalten ListChanged-Ereignisse die Eigenschaftenänderung im ListChangedEventArgs-Parameter). Und stellen Sie sicher, dass die Elemente in der Sammlung INotifyPropertyChange implementieren und verwenden, wenn sich eine Eigenschaft ändert (von Ihnen ausgelöst) oder die Auflistung nicht an Eigenschaftenänderungen bindet.

Dann wird in dieser OnPropertyChanged-Methode der Absender das Element sein. Entfernen Sie das Element, wenn - und nur wenn - eine Eigenschaft, die ein Resort verursachen würde, geändert wird, und fügen Sie sie erneut hinzu (fügen Sie sie an der sortierten Position ein, wenn das Hinzufügen dies nicht bereits tut). Das Verschieben eines Gegenstands ist vorzuziehen, wenn es verfügbar ist, anstatt es zu entfernen / hinzuzufügen. In ähnlicher Weise sollte dies auch mit Filtern geschehen (Überprüfung des Filterprädikats).

IEditableObject wird nicht benötigt! Wenn Sie mehrere Eigenschaften bearbeiten möchten, beenden Sie die Bearbeitung (wie das Bearbeiten von 3 Eigenschaften und dann die Auswahl in einer anderen Zeile in WinForm DataGridView). Wenn Sie dann sortieren, wäre dies die richtige Methode, um dies zu erreichen. Aber oft möchten Sie wahrscheinlich, dass die Sammlung nach dem Ändern jeder Eigenschaft zurückgreift, ohne BeginEdit / EndEdit manuell aufrufen zu müssen. IEditableObject, BTW, ist im .NET 2.0-Framework vorhanden und ist nicht neu in .NET 3.5 (wenn Sie den Artikel des Dr.'s lesen).

Hinweis: Probleme können auftreten, wenn Sie BeginEdit () und EndEdit () mit mehreren Änderungen an demselben Element ausführen - es sei denn, Sie erhöhen (für true) / dekrement (für false) eine Ganzzahl, anstatt einen Booleschen Wert festzulegen! Denken Sie daran, eine Ganzzahl zu erhöhen / verringern, um wirklich zu wissen, wann die Bearbeitung beendet ist.

Das Beibehalten einer ständig sortierten Liste ist zeitaufwendig und fehleranfällig (und kann den Einfügekontrakt unterbrechen, wenn Sie sortierte Einfügungen erzwingen) und sollte nur an bestimmten Stellen wie ComboBoxen verwendet werden. In jedem Raster ist dies eine sehr schlechte Idee, da das Ändern einer Zeile dazu führt, dass sie unter der aktuellen Position des Benutzers ausläuft.

%Vor%

Das beste Beispiel für eine Sammlung, die ähnliche Funktionen wie Jesse Johnsons ObjectListView bietet, ist zwar .NET 2.0-spezifisch (IBindingList statt INotifyCollectionChanged / ObservableCollection / ListCollectionView) und verwendet eine sehr restriktive Lizenz. Sein Blog kann immer noch sehr wertvoll sein, wie er das erreicht hat.

Bearbeiten:

Sie haben vergessen, dass der Absender das Objekt ist, das Sie zurückgeben müssen, und e.PropertyName ist das, was Sie benötigen, um zu bestimmen, ob es in den SortDescriptions enthalten ist. Wenn dies nicht der Fall ist, führt eine Änderung dieser Eigenschaft nicht dazu, dass ein Resort benötigt wird. Wenn e.PropertyName Nothing ist, dann ist es wie bei einer Aktualisierung, bei der sich viele Eigenschaften geändert haben und das Umsortieren vorgenommen werden sollte.

Um festzustellen, ob es gefiltert werden muss, führen Sie es einfach durch das FilterPredicate und entfernen Sie es bei Bedarf. Filtern ist viel billiger als Sortieren.

Hoffentlich hilfreich,

TamusJRoyce

    
TamusJRoyce 26.05.2010 09:51
quelle

Tags und Links