Weiß jemand, warum dieser Code nicht funktioniert:
public class CollectionViewModel : ViewModelBase {
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
set
{
_contentList = value;
RaisePropertyChanged("ContentList");
//I want to be notified here when something changes..?
//debugger doesn't stop here when IsRowChecked is toggled
}
}
}
public class EntityViewModel : ViewModelBase
{
private bool _isRowChecked;
public bool IsRowChecked
{
get { return _isRowChecked; }
set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
}
}
ViewModelBase
enthält alles für RaisePropertyChanged
etc. und es funktioniert für alles andere außer diesem Problem ..
c#
observablecollection
inotifypropertychanged
Joseph jun. Melettukunnel
quelle
quelle
Antworten:
Die Set-Methode von ContentList wird nicht aufgerufen, wenn Sie einen Wert in der Auflistung ändern. Stattdessen sollten Sie auf das Auslösen des CollectionChanged- Ereignisses achten.
Okay, das ist heute zweimal so. Ich wurde von der falschen MSDN-Dokumentation gebissen. In dem Link, den ich dir gegeben habe, heißt es:
Aber es wird tatsächlich nicht ausgelöst, wenn ein Gegenstand geändert wird. Dann brauchen Sie wohl eine Bruteforce-Methode:
Wenn Sie dies häufig benötigen, möchten Sie möglicherweise eine eigene Unterklasse erstellen
ObservableCollection
, die dasCollectionChanged
Ereignis auslöst , wenn ein Mitglied seinPropertyChanged
Ereignis automatisch auslöst (wie in der Dokumentation angegeben ...).quelle
changed
? Dies kann bedeuten, dass sich eine Eigenschaft eines der Elemente in der Sammlung geändert hat (wie Sie es meiner Meinung nach interpretieren), oder dass eines der Elemente der Sammlung geändert wurde, indem es durch eine andere Instanz ersetzt wurde ( das ist meine Interpretation). Nicht ganz überzeugt - muss weiter untersucht werden._contentList.Clear()
? Niemand wird sich abmeldenPropertyChanged
!ContentCollectionChanged
nur Hinzufügen / Entfernen und nicht Ersetzen / Zurücksetzen. Ich werde versuchen, den Beitrag zu bearbeiten und zu reparieren. Die Art und Weise, wie Simon es in seiner Antwort tut, ist richtig.Hier ist eine Drop-In-Klasse, die ObservableCollection unterordnet und tatsächlich eine Reset-Aktion auslöst, wenn sich eine Eigenschaft für ein Listenelement ändert. Es erzwingt die Implementierung aller Elemente
INotifyPropertyChanged
.Der Vorteil hierbei ist, dass Sie Daten an diese Klasse binden können und alle Ihre Bindungen mit Änderungen an Ihren Elementeigenschaften aktualisiert werden.
quelle
NotifyCollectionChangedAction.Replace
ist keine gute Idee, da Sie dann nicht zwischen einem tatsächlich zu ersetzenden Element oder einem durch eine Elementänderung verursachten Ereignis unterscheiden können. Es wird viel besser, wenn Sie definierenpublic event PropertyChangedEventHandler CollectionItemChanged;
und dann inItemPropertyChanged
dothis.CollectionItemChanged?.Invoke(sender, e);
Ich habe eine hoffentlich ziemlich robuste Lösung zusammengestellt, einschließlich einiger Techniken in anderen Antworten. Es ist eine neue Klasse, von
ObservableCollection<>
der ich rufeFullyObservableCollection<>
Es hat die folgenden Funktionen:
ItemPropertyChanged
. Ich habe dies bewusst von den bestehenden getrenntCollectionChanged
:ItemPropertyChangedEventArgs
Begleitmaterial relevantere Details angegeben werden : das OriginalPropertyChangedEventArgs
und der Index innerhalb der Sammlung.ObservableCollection<>
.ObservableCollection<>.Clear()
), wodurch ein möglicher Speicherverlust vermieden wird.OnCollectionChanged()
und nicht ein ressourcenintensiveres Abonnement für dasCollectionChanged
Ereignis.Code
Die vollständige
.cs
Datei folgt. Beachten Sie, dass einige Funktionen von C # 6 verwendet wurden, die Rückportierung jedoch recht einfach sein sollte:NUnit-Tests
Damit Sie überprüfen können, welche Änderungen Sie möglicherweise vornehmen (und sehen, was ich zuerst getestet habe!), Habe ich auch meine NUnit-Testklasse aufgenommen. Offensichtlich ist der folgende Code nicht nur für die Verwendung
FullyObservableCollection<T>
in Ihrem Projekt erforderlich .NB Die Testklasse verwendet
BindableBase
PRISM zur ImplementierungINotifyPropertyChanged
. Es besteht keine Abhängigkeit von PRISM vom Hauptcode.quelle
ListView
wird aufCollectionChanged
Ereignisse reagieren, weil es über sie weiß.ItemPropertyChanged
ist eine nicht standardmäßige Ergänzung, daher müssen Sie sie darüber unterrichten. Als schnelle und schmutzige Lösung können Sie versuchen, dasCollectionChanged
Ereignis sowohl als auch (oder sogar anstelle von)ItemPropertyChanged
auszulösenOnItemPropertyChanged()
. Ich habe sie aus den in der Antwort angegebenen Gründen getrennt gehalten, aber für Ihren Anwendungsfall könnte es genau das tun, was Sie brauchen.Dies verwendet die oben genannten Ideen, macht es jedoch zu einer abgeleiteten "sensibleren" Sammlung:
quelle
ObservableCollection gibt einzelne Elementänderungen nicht als CollectionChanged-Ereignisse weiter. Sie müssen entweder jedes Ereignis abonnieren und manuell weiterleiten, oder Sie können die BindingList [T] -Klasse auschecken , die dies für Sie erledigt .
quelle
Zum TruelyObservableCollection-Ereignis "ItemPropertyChanged" hinzugefügt:
quelle
Ich habe Jack Kenyons Antwort verwendet, um mein eigenes OK zu implementieren, aber ich möchte auf eine Änderung hinweisen, die ich vornehmen musste, damit es funktioniert. Anstatt:
Ich habe das benutzt:
Es scheint, dass "e.NewItems" null erzeugt, wenn die Aktion .Remove ist.
quelle
Ich füge nur meine 2 Cent zu diesem Thema hinzu. Für die TrulyObservableCollection waren die beiden anderen Konstruktoren erforderlich, die mit ObservableCollection gefunden wurden:
quelle
Ich weiß, dass ich für diese Party zu spät bin, aber vielleicht - es wird jemandem helfen.
Hier finden Sie meine Implementierung von ObservableCollectionEx. Es hat einige Funktionen:
Kommentare sind natürlich willkommen;)
quelle
Wenn ich ObservableCollection kenne, mache ich nur dann ein Ereignis, wenn wir Elemente in unserer Sammlung hinzufügen / löschen oder verschieben. Wenn wir einige Eigenschaften in der Sammlung von Sammlungselementen einfach aktualisieren, signalisieren wir dies nicht und die Benutzeroberfläche wird nicht aktualisiert.
Sie können INotifyPropertyChange einfach in Ihrer Model-Klasse implementieren . Und dann, wenn wir einige Eigenschaften im Sammlungselement aktualisieren, wird die Benutzeroberfläche automatisch aktualisiert.
und dann
In meinem Fall habe ich ListView to Bind für diese Sammlung verwendet und in ItemTemplate die Eigenschaft Binding to Model festgelegt, und es funktioniert gut.
Hier ist ein Ausschnitt
Windows XAML:
Modellcodebeispiel:
Und ViewModel-Implementierung:
quelle
Einfache Lösung für die standardmäßige beobachtbare Sammlung, die ich verwendet habe:
NICHT ZU DEM EIGENTUM HINZUFÜGEN ODER DIE inneren Elemente DIREKT ÄNDERN, sondern eine temporäre Sammlung wie diese erstellen
und Elemente hinzufügen oder Änderungen an tmpList vornehmen,
Übergeben Sie es dann durch Abtretung an Ihr eigentliches Eigentum.
Dadurch wird die gesamte Eigenschaft geändert, wodurch INotifyPropertyChanged nach Bedarf angezeigt wird.
quelle
Ich versuche diese Lösung, arbeite aber nur für mich wie eine RaisePropertyChange ("SourceGroupeGridView"), wenn die Sammlung geändert wurde, die für jedes hinzugefügte oder geänderte Element ausgelöst wurde.
Das Problem liegt in:
NotifyCollectionChangedAction.Reset Diese Aktion führt eine vollständige Neubindung aller Elemente in groupedgrid durch. Dies entspricht RaisePropertyChanged. Wenn Sie es verwenden, werden alle Gruppen der Rasteransicht aktualisiert.
Wenn Sie nur die Gruppe des neuen Elements in der Benutzeroberfläche aktualisieren möchten und die Aktion "Zurücksetzen" nicht verwenden, müssen Sie eine Aktion "Hinzufügen" in itemproperty mit folgendem Ergebnis simulieren:
Entschuldigung für mein Englisch und danke für den Basiscode :), ich hoffe das hilft jemandem ^ _ ^
Enjoi !!
quelle
Hier ist eine Erweiterungsmethode für die obige Lösung ...
quelle
Verwenden Sie anstelle einer ObservableCollection oder TrulyObservableCollection eine BindingList und rufen Sie die ResetBindings-Methode auf.
Beispielsweise:
Bei einem Ereignis wie einem Klick würde Ihr Code folgendermaßen aussehen:
Mein Modell sah so aus:
quelle
BindingList
, aber es gibt eine Einschränkung für diesen Ansatz, die die anderen Antworten überwinden: Diese Technik hängt davon ab,ResetBindings()
welcher Wert im Code geändert wird und wo ein Aufruf hinzugefügt werden kann. Die meisten anderen Antworten funktionieren, wenn die Objekte der Liste auf andere Weise geändert werden, z. B. durch unveränderlichen Code oder von einer Bindung an ein zweites Steuerelement.So lösen Sie OnChange in der ObservableCollection-Liste aus
Beispiel:
quelle
Hier ist meine Version der Implementierung. Es prüft und löst einen Fehler aus, wenn die Objekte in der Liste INotifyPropertyChanged nicht implementieren, sodass dieses Problem während der Entwicklung nicht vergessen werden kann. Außen verwenden Sie das ListItemChanged-Ereignis, um festzustellen, ob sich die Liste oder das Listenelement selbst geändert hat.
quelle
Einfache Lösung in 2 Codezeilen. Verwenden Sie einfach den Kopierkonstruktor. Sie müssen TrulyObservableCollection usw. nicht schreiben.
Beispiel:
Eine andere Methode ohne Kopierkonstruktor. Sie können die Serialisierung verwenden.
quelle
Mit dieser Erweiterungsmethode können Sie auch einfach einen Handler für die Änderung von Elementeigenschaften in relevanten Sammlungen registrieren. Diese Methode wird automatisch allen Sammlungen hinzugefügt, die INotifyCollectionChanged implementieren und Elemente enthalten, die INotifyPropertyChanged implementieren:
Wie benutzt man:
quelle