How to implement INotifyPropertyChanged in C# 6.0?

The answer to this question has been edited to say that in C# 6.0, INotifyPropertyChanged can be implemented with the following OnPropertyChanged procedure:

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

However, it isn't clear from that answer what the corresponding property definition should be. What does a complete implementation of INotifyPropertyChanged look like in C# 6.0 when this construction is used?


Solution 1:

After incorporating the various changes, the code will look like this. I've highlighted with comments the parts that changed and how each one helps

public class Data : INotifyPropertyChanged
{ 
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        //C# 6 null-safe operator. No need to check for event listeners
        //If there are no listeners, this will be a noop
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // C# 5 - CallMemberName means we don't need to pass the property's name
    protected bool SetField<T>(ref T field, T value,
    [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) 
            return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    private string name;
    public string Name
    {
        get { return name; }
        //C# 5 no need to pass the property name anymore
        set { SetField(ref name, value); }
    }
}

Solution 2:

I use the same logic in my project. I have a base class for all view models in my app:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Every view model inherits from this class. Now, in the setter of each property I just need to call OnPropertyChanged().

public class EveryViewModel : PropertyChangedBase
{
    private bool initialized;
    public bool Initialized
    {
        get
        {
            return initialized;
        }
        set
        {
            if (initialized != value)
            {
                initialized = value;
                OnPropertyChanged();
            }
        }
    }

Why does it work?

[CallerMemberName] is automatically populated by the compiler with the name of the member who calls this function. When we call OnPropertyChanged from Initialized, the compiler puts nameof(Initialized) as the parameter to OnPropertyChanged

Another important detail to keep in mind

The framework requires that PropertyChanged and all properties that you're binding to are public.

Solution 3:

I know this question is old, but here is my implementation

Bindable uses a dictionary as a property store. It's easy enough to add the necessary overloads for a subclass to manage its own backing field using ref parameters.

  • No magic string
  • No reflection
  • Can be improved to suppress the default dictionary lookup

The code:

    public class Bindable : INotifyPropertyChanged
    {
        private Dictionary<string, object> _properties = new Dictionary<string, object>();

        /// <summary>
        /// Gets the value of a property
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        protected T Get<T>([CallerMemberName] string name = null)
        {
            object value = null;
            if (_properties.TryGetValue(name, out value))
                return value == null ? default(T) : (T)value;
            return default(T);
        }

        /// <summary>
        /// Sets the value of a property
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="name"></param>
        protected void Set<T>(T value, [CallerMemberName] string name = null)
        {
            if (Equals(value, Get<T>(name)))
                return;
            _properties[name] = value;
            OnPropertyChanged(name);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

used like this

public class Item : Bindable
{
     public Guid Id { get { return Get<Guid>(); } set { Set<Guid>(value); } }
}