Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing INotifyPropertyChanged for nested properties

I have a Person class:

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
}

I have an Address class:

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
}

I have a 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" );
           }
     }

}

I have a View which has the following lines:

<TextBox  Text="{Binding Person.Name, Mode=TwoWay,   
    UpdateSourceTrigger=PropertyChanged />

<TextBox  Text="{Binding Person.Address.StreetOne, Mode=TwoWay,   
    UpdateSourceTrigger=PropertyChanged />

Both values show up in the text box ok when the view loads.

Changes to the first text box will fire OnPropertyChanged( "Person" ) in MyViewModel. Great.

Changes to the second text box ("Person.Address.StreetOne") does NOT fire OnPropertyChanged( "Person" ) inside MyViewModel. Meaning it doesn't call the Person object's SET method. Not great. Interestingly the SET method of StreetOne inside the Address class is called.

How do I get the SET method of the Person object inside the ViewModel to be called when Person.Address.StreetOne is changed???

Do I need to flatten my data so SteetOne is inside Person and not Address??

Thanks!

like image 893
lloyd christmas Avatar asked Aug 08 '12 17:08

lloyd christmas


People also ask

How do you implement INotifyPropertyChanged?

To implement INotifyPropertyChanged you need to declare the PropertyChanged event and create the OnPropertyChanged method. Then for each property you want change notifications for, you call OnPropertyChanged whenever the property is updated.

What is the INotifyPropertyChanged interface?

INotifyPropertyChanged is an interface member in System. ComponentModel Namespace. This interface is used to notify the Control that the property value has changed.

What is INotifyPropertyChanged in WPF?

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed. For example, consider a Person object with a property called FirstName .

What is INotifyPropertyChanged xamarin?

The INotifyPropertyChanged changed interface is at the heart of XAML apps and has been a part of the . NET ecosystem since the early days of Windows Forms. The PropertyChanged event notifies the UI that a property in the binding source (usually the ViewModel) has changed. It allows the UI to update accordingly.


1 Answers

While adding 'pass-through' properties to your ViewModel is a fine solution, it can quickly become untenable. The standard alternative is to propagate changes as below:

  public Address PrimaryAddress {
     get => _primaryAddress;
     set {
           if ( _primaryAddress != value ) 
           {
             //Clean-up old event handler:
             if(_primaryAddress != null)
               _primaryAddress.PropertyChanged -= AddressChanged;

             _primaryAddress = value;

             if (_primaryAddress != null)
               _primaryAddress.PropertyChanged += AddressChanged;

             OnPropertyChanged( "PrimaryAddress" );
           }

           void AddressChanged(object sender, PropertyChangedEventArgs args) 
               => OnPropertyChanged("PrimaryAddress");
        }
  }

Now change notifications are propagated from Address to person.

Edit: Moved handler to c# 7 local function.

like image 155
Andrew Hanlon Avatar answered Sep 18 '22 16:09

Andrew Hanlon