An elegant INotifyPropertyChanged implementation #4

This is the last part of a series of articles discussing an optimal implementation of the INotifyPropertyChanged event. As we’ve managed to implement a maintainable bindable property declaration by removing all string references, there are still two open questions left: How can we reduce the amount of code needed for one property declaration, thus reducing the effort in actually writing the code and at the same time making the resulting code more readable?

In a first step, let’s try to reduce the actual property declaration code to as few lines as possible! Unfortunately, we won’t ever be able to use auto-properties since we need to intercept the property’s setter method, so there’s no way to get rid of the backing field or the manual implementation of getter and setter method – however, we can shorten those! The property’s getter is already as short as possible, containing just one line that returns the backing field’s content. In contrast, the setter method is quite verbose and can surely be simplified!

Remember that, as I shortly mentioned in the first part of this article series, a typical bindable property’s setter method needs to do the following things:

  1. Compare old and new value, (to ensure PropertyChanged is only raised on actual changes),
  2. if the two are different, set the backing field’s value,
  3. raise the property’s PropertyChanged event,
  4. optionally raise other properties’ PropertyChanged events (in case some other properties depend on the current one),
  5. and optionally raise some Commands’ CanExecuteChanged events (in case some Commands’ execute conditions depend on the current property)

The first three steps are necessary for all bindable properties, the fourth one is optional. The fifth step (informing some Command that its execute condition has changed) can actually be omitted and moved to the actual Command’s implementation (I’m planning a separate article explaining this smart ICommand implementation in detail), so I’ll ignore this step for the time being.

To make the property setter shorter and more readable, we simply move all the contained code to a generic helper method that can be called from within every property declaration! I call this helper method Set(), since that describes quite well what it’s doing (and is a name as short as possible), and its signature looks like this:

protected void Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)

As you can see, we pass the backing field (by reference, since we’ll need to update it’s content!), the new value, and the property name (for raising the PropertyChanged event). The latter can be omitted to be automatically replaced by the calling property’s name, as we’ve learned in part #2 of this series.

Now we’re ready to fill in the Set method’s body to make it process all the steps listed above. First, to compare old and new value, we can not rely on type-specific comparison method (such as String.Equals(...)) any more, since the Set method shall work for all types. Instead, I suggest using the Object.ReferenceEquals method that checks whether two object instance are the same instance:

if (!ReferenceEquals(field, value))
{
	....
}

Replacing the backing field’s old value with the new one is a simple assignment, and raising the PropertyChanged event is not difficult either since we can rely on the RaisePropertyChanged method defined earlier (we just need make sure that we pass the property name explicitly this time, otherwise the PropertyChanged will be raised with a parameter that says Set instead of the actual property name!):

protected void Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
	if (!ReferenceEquals(field, value))
	{
		field = value;
		RaisePropertyChanged(propertyName);
	}
}

This implementation covers the first three (mandatory) steps listed above. In order to also take care of the fourth one (the optional), we could create an overload of the Set method that accepts an additional dependent property whose PropertyChanged event shall also be raised:

protected void Set<T>(ref T field, T value, Expression<Func<T>> dependentProperty,
                      [CallerMemberName] string propertyName = null)
{
	if (!ReferenceEquals(field, value))
	{
		field = value;
		RaisePropertyChanged(propertyName);
		RaisePropertyChanged(dependentProperty);
	}
}

(Of course, in some cases it might be necessary to raise the PropertyChanged event for multiple dependent properties, in this case we’d need another overload that accepts a collection of additional properties, but for the sake of simplicity I omit this step for now.)

One final step can be done to reduce the amount of code and at the same time make the code more maintainable: We should relocate both the RaisePropertyChanged methods and the Set methods to a separate class – let’s name it BaseViewmodel that every production Viewmodel can inherit from:

public void BaseViewmodel : INotifyPropertyChanged
{
		public event PropertyChangedEventHandler PropertyChanged;

		protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
		{
			PropertyChangedEventHandler handler = PropertyChanged;
			if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
		}

		protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> property)
		{
			string propertyName = ((MemberExpression)property.Body).Member.Name;
			RaisePropertyChanged(propertyName);
		}

		protected void Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
		{
			if (!ReferenceEquals(field, value))
			{
				field = value;
				RaisePropertyChanged(propertyName);
			}
		}

		protected void Set<T>(ref T field, T value, Expression<Func<T>> dependentProperty,
		                      [CallerMemberName] string propertyName = null)
		{
			if (!ReferenceEquals(field, value))
			{
				field = value;
				RaisePropertyChanged(propertyName);
				RaisePropertyChanged(dependentProperty);
			}
		}
}

This way, we’ll never ever need to write those methods again, just reference the BaseViewmodel class! So our sample PersonViewmodel class looks as clean as:

class PersonViewmodel : BaseViewmodel
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { Set(ref _firstName, value, () => FullName); }
    }
 
    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set { Set(ref _lastName, value, () => FullName); }
    }
 
    public string FullName
    {
        get { return String.Format("{0} {1}", FirstName, LastName); }
    }
}

Unfortunately, this is as far as we get. The only way to make these bindable property declarations even shorter would be the use of auto-properties (e.g., public string FirstName { get; set; }) – however, you won’t be able to pack the PropertyChanged event raising mechanism into these. With current technology (.NET 4.5, C# 6) it’s not possible to adapt a property’s setter method (and, for example, inject the RaisePropertyChanged call into it), not even using Reflection.

That said, there are in fact ways to make auto-properties bindable (there exist libraries out there that allow using Attribute-marked auto-properties), but these build on IL code instead of the C# language. Since this is kind of a different story, I’ll discuss this approach in a separate series of articles