Die Implementierung von INotifyPropertyChanged für verschachtelte Eigenschaften
Ich habe eine Klasse "Person":
public class Person : INotifyPropertyChanged
{
private string _name;
public string Name{
get { return _name; }
set {
if ( _name != value ) {
_name = value;
OnPropertyChanged( "Name" );
}
}
private Address _primaryAddress;
public Address PrimaryAddress {
get { return _primaryAddress; }
set {
if ( _primaryAddress != value ) {
_primaryAddress = value;
OnPropertyChanged( "PrimaryAddress" );
}
}
//OnPropertyChanged code goes here
}
Ich habe eine Adresse der Klasse:
public class Address : INotifyPropertyChanged
{
private string _streetone;
public string StreetOne{
get { return _streetone; }
set {
if ( _streetone != value ) {
_streetone = value;
OnPropertyChanged( "StreetOne" );
}
}
//Other fields here
//OnPropertyChanged code goes here
}
Habe ich ein ViewModel:
public class MyViewModel
{
//constructor and other stuff here
private Person _person;
public Person Person{
get { return _person; }
set {
if ( _person != value ) {
_person = value;
OnPropertyChanged( "Person" );
}
}
}
Ich habe eine Ansicht mit den folgenden Zeilen:
<TextBox Text="{Binding Person.Name, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged />
<TextBox Text="{Binding Person.Address.StreetOne, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged />
Beide Werte zeigen sich in der text-box ok, wenn die Ansicht geladen.
Änderungen in das erste Textfeld wird Feuer OnPropertyChanged( "Person" )
im MyViewModel. Toll.
Änderungen in das zweite Textfeld ("Person.Address.StreetOne")
NICHT Feuer OnPropertyChanged( "Person" )
innen MyViewModel. Das heißt nicht, rufen Sie die Person-Objekt-SATZ-Methode. Nicht so toll. Interessanterweise ist die SET-Methode von StreetOne innerhalb der Address-Klasse aufgerufen wird.
Wie bekomme ich die SET-Methode der Person-Objekt in der ViewModel aufgerufen wird, wenn Person.Address.StreetOne
geändert wird???
Muss ich reduzieren meine Daten so SteetOne ist im inneren Menschen und nicht die Adresse??
Dank!
- Bezüglich deiner Güte die Frage bereits beantwortet wurde. Also, welche Art von Antwort Sie suchen, hier?
- die akzeptierte Antwort ist ein workaround ist die Abflachung der Eigenschaft.. ich war auf der Suche für eine echte Lösung
- Ich fügte hinzu, eine Antwort mit der standard-alternative, die zu propagieren der änderungen vom Kind zu den Eltern mit einem event-handler. Ich bin nicht sicher, wie dies übersehen wurde in der ursprünglichen Antworten, da es ziemlich standard ist und eine "echte" Lösung.
- danke!
Du musst angemeldet sein, um einen Kommentar abzugeben.
wenn Sie möchten, dass die viewmodel-SATZ genannt zu werden, Sie könnte eine Straße die Eigenschaft
xaml
aber diese Lösung hat auch Ihre Nachteile. ich gehe mit Schilf Antwort in meinen Projekten
Während das hinzufügen von 'pass-through' - Eigenschaften auf der ViewModel ist eine feine Lösung, kann es schnell unhaltbar geworden. Die standard-alternative ist zum weitergeben von änderungen wie folgt:
Nun ändern Benachrichtigungen weitergegeben, von der Adresse auf die person.
Edit: Verschoben handler in c# 7 lokale Funktion.
protected bool SetBindableField<T>(ref T field, T value, [CallerMemberName] string propertyName = null) where T : INotifyPropertyChanged
. Mit CallerMemberName, um die Eigenschaft name ist ein life saver (ich hatte vielleicht mehr als einen falschen parameter name Fehler bei der Verwendung einer copy-paste-Ansatz, um dies zu testen).if (field != null)
vor der Zuweisung der event-handler auf das Feld. In meinem Fall mache ich null zuweisen der Eigenschaft, da gibt es einige Fälle, in denen es nicht benötigt wird. Ich habe die verschachtelten Objekte zugeordnet separaten Tabellen in einer SQLite-Datenbank (mit EFCore, foreign keys) und die Einträge müssen null sein, wenn nicht verwendet. Es funktioniert gut mit ändern.Warum wollen Sie dies tun? Es sollte nicht erforderlich sein - Sie brauchen nur die
StreetOne
property-changed-Ereignis ausgelöst.Wenn Sie wollen, um tatsächlich dazu führen, dass dies trigger, brauchen Sie nicht zu glätten (auch wenn das ist eine option). Sie können sich in die
Address
'sPropertyChanged
Ereignis in Ihrem Person-Klasse, und heben Sie die Veranstaltung für "Adresse" innerhalbPerson
wenn Sie sich ändert. Dies sollte nicht notwendig sein, aber.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
für die).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
wird "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.Es 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 705450, wo 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
Es ist ein Schreibfehler in Ihrer Eigenschaft Meldung ändern:
OnPropertyChanged( "SteetOne" );
sollte
OnPropertyChanged( "StreetOne" );