UWP Basics

  • 10/11/2018

Notifying the Binding about Changes to Source Properties

The INotifyPropertyChanged interface contains a declaration of the PropertyChanged event. You use this event in the derived class to notify the data-binding mechanism about changes in the source properties of the ViewModel. This functionality is necessary for apps using one-way binding. To implement notifications, you typically create the base class, which derives from INotifyPropertyChanged. This class handles all the logic related to notifying data binding about changes in source properties and becomes the base class for all other ViewModels.

To give you an example, I supplemented the MixedReality.Common project with another file, BaseViewModel.cs (in the ViewModels folder), in which I define the class shown in Listing 4-13.

LISTING 4-13 A definition of the BaseViewModel class

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected void SetProperty<T>(ref T property, T value, 
    [CallerMemberName] string propertyName = "")
    {
        property = value;
        OnPropertyChanged(propertyName);
    }
}

The BaseViewModel class derives from the INotifyPropertyChanged interface and thus implements a PropertyChanged event of type PropertyChangedEventHandler. This event represents the method, which accepts two arguments:

  • sender of type object This stores a reference to the object, which raises an event.

  • e of type PropertyChangedEventArgs This is used to pass the name of the source property that was updated.

You use these arguments to raise the PropertyChanged event. Listing 4-13 fires this event in the OnPropertyChanged method. The latter accepts one argument, propertyName, which is used to instantiate PropertyChangedEventArgs. OnPropertyChanged is used to implement a generic SetProperty function, which is responsible for updating the selected property of the ViewModel and providing appropriate notification to the data binding. As Listing 4-13 shows, SetProperty accepts three arguments:

  • property This is the property to be updated.

  • value This is a new value, to be written to the property being updated.

  • propertyName This is an optional argument that specifies the name of the property. By default, propertyName is inferred from the property argument. However, you can use propertyName to explicitly inform the data-binding mechanism which property has changed.

You can skip the last argument, propertyName, when calling the SetProperty method. In this case, it will deduct the property name from the call to that method. This is indicated by the CallerMemberName attribute. (See http://bit.ly/callermembername for more information.)

After preparing the BaseViewModel class, use it to modify the PersonViewModel. (See Listing 4-14.) First, update the declaration of the PersonViewModel class so it derives from BaseViewModel. Next, replace three auto-implemented properties—FirstName, LastName, and Age—with new versions that explicitly implement property get and set accessors. In each case, the get accessor returns the value from the underlying private field, while the set accessor uses the base SetProperty method. This ensures that the data-binding mechanism will be notified about updates to public properties of the ViewModel.

LISTING 4-14 Notifying data binding about changes in source properties

public class PersonViewModel : BaseViewModel
{
    //public string FirstName { get; set; }
    //public string LastName { get; set; }
    //public int Age { get; set; }

    public string FirstName
    {
        get => firstName;
        set => SetProperty(ref firstName, value);
    }

    public string LastName
    {
        get => lastName;
        set => SetProperty(ref lastName, value);
    }

    public int Age
    {
        get => age;
        set => SetProperty(ref age, value);
    }

    private string firstName;
    private string lastName;
    private int age;

    // The rest of class definition
}

After introducing these changes, re-run the app. You will see that all changes to source properties are automatically reflected in the UI and that the converter works correctly each time you modify the last name. The data-binding mechanism recognizes that PersonViewModel uses a PropertyChanged event from the INotifyPropertyChanged interface and automatically registers for change notifications.

Related resources

There are currently no related titles.