Abonnieren Sie INotifyPropertyChanged für verschachtelte (untergeordnete) Objekte
Ich bin auf der Suche nach einem sauberen und elegante Lösung zu behandeln, die INotifyPropertyChanged
Falle verschachtelte (untergeordnete) Objekte. Beispiel-code:
public class Person : INotifyPropertyChanged {
private string _firstName;
private int _age;
private Person _bestFriend;
public string FirstName {
get { return _firstName; }
set {
//Short implementation for simplicity reasons
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
public int Age {
get { return _age; }
set {
//Short implementation for simplicity reasons
_age = value;
RaisePropertyChanged("Age");
}
}
public Person BestFriend {
get { return _bestFriend; }
set {
//- Unsubscribe from _bestFriend's INotifyPropertyChanged Event
// if not null
_bestFriend = value;
RaisePropertyChanged("BestFriend");
//- Subscribe to _bestFriend's INotifyPropertyChanged Event if not null
//- When _bestFriend's INotifyPropertyChanged Event is fired, i'd like
// to have the RaisePropertyChanged("BestFriend") method invoked
//- Also, I guess some kind of *weak* event handler is required
// if a Person instance i beeing destroyed
}
}
//**INotifyPropertyChanged implementation**
//Implementation of RaisePropertyChanged method
}
Fokus auf die BestFriend
Eigenschaft und die value-setter. Jetzt ich weiß, dass ich könnte dies manuell tunder Umsetzung sämtlicher Schritte in die Kommentare. Aber das wird eine Menge von code, vor allem, wenn ich Plane, viele untergeordnete Eigenschaften der Implementierung INotifyPropertyChanged
wie diese. Natürlich sind Sie nicht immer von derselben Art, das einzige, was Sie gemeinsam haben, ist die INotifyPropertyChanged
- Schnittstelle.
Der Grund dafür ist, dass in meinem realen Szenario, ich habe einen Komplex "Item" (in den Warenkorb) Objekt, das die verschachtelte Objekt-Eigenschaften über mehrere Ebenen (Element ist, das eine "Lizenz" - Objekt, das können sich untergeordnete Objekte wieder) und ich brauche, um benachrichtigt zu werden, über jede einzelne änderung der "Position" in der Lage sein, um eine Neuberechnung der Preis.
Haben Sie einige gute Tipps, oder sogar einige
Umsetzung zu helfen, mich zu lösen
diese?
Leider bin ich nicht in der Lage/dürfen, verwenden Sie den post-build-Schritte wie PostSharp zu erreichen, mein Ziel.
Vielen Dank im Voraus,
- Thomas
InformationsquelleAutor der Frage thmshd | 2010-11-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
da war ich nicht in der Lage zu finden, eine ready-to-use-Lösung, die ich getan habe, um eine benutzerdefinierte Implementierung basiert auf Pieters (und Marken) Anregungen (vielen Dank!).
Durch die Verwendung der Klassen, erhalten Sie eine Benachrichtigung über jede änderung in ein tief-Objekt Baum, das funktioniert für beliebige
INotifyPropertyChanged
Umsetzung von Arten-undINotifyCollectionChanged
* Durchführung von Sammlungen (Offensichtlich bin ich mit demObservableCollection
).Ich hoffe das erwies sich als eine sehr saubere und elegante Lösung, es ist nicht vollständig getestet, obwohl, und es gibt Raum für Verbesserungen. Es ist ziemlich einfach zu verwenden, erstellen Sie einfach eine Instanz von
ChangeListener
Verwendung der statischenCreate
- Methode auf und übergeben IhrINotifyPropertyChanged
:den
PropertyChangedEventArgs
bieten einePropertyName
werden immer den vollen "Pfad" Ihrer Objekte. Zum Beispiel, wenn Sie ändern die Personen, die "beste Freundin" Namen, diePropertyName
"beste Freundin.Name", wenn dieBestFriend
hat eine Sammlung von Kinder-und ändern Sie es auf das Alter, wird der Wert "beste Freundin.Kinder[].Alter" und so weiter. Vergessen Sie nichtDispose
wenn Ihr ein Objekt zerstört wird, dann wird es (hoffentlich) komplett abbestellen, alle Ereignis-Listener.Kompiliert .NET (Getestet in 4) und Silverlight (Getestet in 4). Da der code in aufgeteilt in drei Klassen, die ich gebucht habe, den code zu gist 705450wo Sie können, greifen es alle: https://gist.github.com/705450 **
*) Ein Grund, dass der code funktioniert ist, dass die
ObservableCollection
auch implementiertINotifyPropertyChanged
ist, sonst wäre es nicht wie gewünscht, dies ist eine bekannte Einschränkung**) Zur kostenlosen Nutzung, veröffentlicht unter MIT-Lizenz
InformationsquelleAutor der Antwort thmshd
Ich denke was du suchst ist so etwas wie WPF verbindlich.
Wie
INotifyPropertyChanged
funktioniert, ist, dass dieRaisePropertyChanged("BestFriend");
muss nur werden fored, wenn die EigenschaftBestFriend
änderungen. Nicht, wenn alles auf dem Objekt selbst ändert.Wie würden Sie diese umsetzen, ist durch ein zwei-Schritt -
INotifyPropertyChanged
event-handler. Der listener registrieren möchten auf den geänderten Termin derPerson
. Wenn dieBestFriend
wird eingestellt/geändert, Sie registrieren sich auf den geänderten Termin derBestFriend
Person
. Dann starten Sie hören auf veränderte Ereignisse des Objekts.Dies ist genau wie WPF verbindlich implementiert. Das Zuhören änderungen von verschachtelten Objekten erfolgt durch das system.
Der Grund dafür ist nicht zur Arbeit gehen, wenn Sie das umsetzen in
Person
ist, dass die Niveaus sehr tief und das changed-Ereignis vonBestFriend
bedeutet nichts mehr ("was hat sich verändert?"). Dieses problem wird größer, wenn Sie haben kreisförmige Beziehungen, wo z.B. der beste Freund von Ihr monther ist die Mutter Ihrer besten Freundin. Dann, wenn eine der Eigenschaften ändern, erhalten Sie einen stack-überlauf.So, wie würden Sie dies lösen, ist, eine Klasse zu erstellen, mit dem Sie aufbauen können für die Zuhörer. Sie würde zum Beispiel bauen Sie einen listener auf
BestFriend.FirstName
. Diese Klasse würde dann legen Sie eine Ereignisprozedur für das Ereignis geändert vonPerson
und hören Sie die änderungen aufBestFriend
. Dann, wenn sich das ändert, bringt es ein Zuhörer aufBestFriend
und Listener für änderungen vonFirstName
. Dann, wenn sich das ändert, sendet er ein Ereignis auslöst, und Sie können dann hören, dass. Das ist im Grunde, wie WPF-Bindung funktioniert.Sehen http://msdn.microsoft.com/en-us/library/ms750413.aspx weitere Informationen zu WPF verbindlich.
InformationsquelleAutor der Antwort Pieter van Ginkel
Interessante Lösung Thomas.
Ich eine andere Lösung gefunden. Es heißt Propagator design-Muster. Sie können finden Sie mehr über das Internet (z.B. auf CodeProject: Propagator in C# - Alternative zu Observer Design Pattern).
Im Grunde, es ist ein pattern für die Aktualisierung der Objekte in einer Abhängigkeits-Netzwerk. Es ist sehr nützlich, wenn sich der Zustand ändert, müssen geschoben werden durch ein Netzwerk von Objekten. Eine Zustandsänderung wird durch ein Objekt dargestellt selbst die Reise durch das Netzwerk der Multiplikatoren. Durch die Kapselung der Zustand ändern, wie ein Objekt, die Verbreiter werden lose gekoppelt.
Einem Klassendiagramm des re-usable Propagator Klassen:
Lesen Sie mehr auf CodeProject.
InformationsquelleAutor der Antwort Marek Takac
Schrieb ich eine einfache Helfer, um dies zu tun. Rufen Sie einfach BubblePropertyChanged(x => x.Beste Freundin) in Ihrer übergeordneten Ansicht-Modell. n.b. es ist eine Annahme, die man über eine Methode namens NotifyPropertyChagned in Ihre Eltern, aber Sie anpassen können.
InformationsquelleAutor der Antwort DanH
Check-out meine Lösung auf CodeProject:
http://www.codeproject.com/Articles/775831/INotifyPropertyChanged-propagator
Es tut genau, was Sie brauchen - und hilft, Sie zu verbreiten (in eleganter Weise) abhängige Eigenschaften, wenn entsprechende Abhängigkeiten, die in dieser oder einer geschachtelten Modelle anzeigen ändern:
InformationsquelleAutor der Antwort KolA
Habe ich die Suche im Web für einen Tag jetzt, und ich fand eine andere schöne Lösung von Sacha Barber:
http://www.codeproject.com/Articles/166530/A-Chained-Property-Observer
Er erstellt schwache Verweise innerhalb einer Verketteten Eigenschaft Beobachter. Kasse die Artikel, wenn Sie sehen wollen, eine weitere gute Möglichkeit, dieses feature zu implementieren.
Und ich möchte auch erwähnen, eine schöne Umsetzung mit den Reactive Extensions @
http://www.rowanbeach.com/rowan-beach-blog/a-system-reactive-property-change-observer/
Diese Lösung funktioniert nur für eine Ebene des Beobachters, nicht eine vollständige Kette von Beobachtern.
InformationsquelleAutor der Antwort Pascalsz