INotifyPropertyChanged interface

Remarks

The interface INotifyPropertyChanged is needed whenever you need to make your class report the changes happening to its properties. The interface defines a single event PropertyChanged.

With XAML Binding the PropertyChanged event is wired up automatically so you only need to implement the INotifyPropertyChanged interface on your view model or data context classes to work with XAML Binding.

Implementing INotifyPropertyChanged in C# 6

The implementation of INotifyPropertyChange can be error-prone, as the interface requires specifying property name as a string. In order to make the implementation more robust, an attribute CallerMemberName can be used.

class C : INotifyPropertyChanged
{
    // backing field
    int offset;
    // property
    public int Offset
    {
        get
        {
            return offset;
        }
        set
        {
            if (offset == value)
                return;
            offset = value;
            RaisePropertyChanged();
        }
    }

    // helper method for raising PropertyChanged event
    void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    // interface implemetation
    public event PropertyChangedEventHandler PropertyChanged;
}

If you have several classes implementing INotifyPropertyChanged, you may find it useful to refactor out the interface implementation and the helper method to the common base class:

class NotifyPropertyChangedImpl : INotifyPropertyChanged
{
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    // interface implemetation
    public event PropertyChangedEventHandler PropertyChanged;
}

class C : NotifyPropertyChangedImpl
{
    int offset;
    public int Offset
    {
        get { return offset; }
        set { if (offset != value) { offset = value; RaisePropertyChanged(); } }
    }
}

INotifyPropertyChanged With Generic Set Method

The NotifyPropertyChangedBaseclass below defines a generic Set method that can be called from any derived type.

public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
    public event PropertyChangedEventHandler PropertyChanged;

    public virtual bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(field, value))
            return false;
        storage = value;
        RaisePropertyChanged(propertyName);
        return true;
    }
}

To use this generic Set method, you simply need to create a class that derives from NotifyPropertyChangedBase.

public class SomeViewModel : NotifyPropertyChangedBase
{
    private string _foo;
    private int _bar;

    public string Foo
    {
        get { return _foo; }
        set { Set(ref _foo, value); }
    }

    public int Bar
    {
        get { return _bar; }
        set { Set(ref _bar, value); }
    }
}

As shown above, you can call Set(ref _fieldName, value); in a property's setter and it will automatically raise a PropertyChanged event if it is needed.

You can then register to the PropertyChanged event from another class that needs to handle property changes.

public class SomeListener
{
    public SomeListener()
    {
        _vm = new SomeViewModel();
        _vm.PropertyChanged += OnViewModelPropertyChanged;
    }

    private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine($"Property {e.PropertyName} was changed.");
    }

    private readonly SomeViewModel _vm;

}


2016-07-23
2016-10-31
C# Language Pedia
Icon