Menu

Notifying objects

Alexey Popov

Notifying objects in Masamune

Masamune provides base classes for view models. The base class for simple objects is called NotifyingObject and the base class for collections is called NotifyingCollection. These classes provide facilities for property changes notifications and their management throug the IUpdatable interface.

This interface is designed to support bulk updates and declares two methods: BeginUpdate() and EndUpdate(). When a type implements it, the first method should stop rising notification events and the second - resume them. Thus the type should support a bit flag signalling if the notifications enabled or not.

It may be a good idea to send a notification that the object has been completely changed in the EndUpdate() method implementation.

To simplify use of the interface Masamune provides two utility types: the UpdateLock<T> struct and the UpdateLock class.

UpdateLock<T> struct

This struct implements the System.IDisposable interface, calls the IUpdatable.BeginUpdate() in it's constructor and the IUpdatable.EndUpdate() in it's Dispose() method.

Suppose you have a class MyUpdatable that implements the IUpdatable interface. To bulk update the instance of the class use the following code:

MyUpdatable instance = GetMyUpdatable();
using(UpdateLock<MyUpdatable> l = new UpdateLock<MyUpdatable>(instance))
{
    // Update the 'instance'
}

UpdateLock class

This static utility class helps one to simplify the code for bulk updates:

MyUpdatable instance = GetMyUpdatable();
using(var l = UpdateLock.Acquire(instance))
{
    // Update the 'instance'
}

It uses C# type inference to make the using statement clearer.

NotifyingObject class

The NotifyingObject is an abstract base for classes that support notifications. It implements both System.ComponentModel.INotifyPropertyChanged and IUpdatable interfaces and defines following members:

  • A protected constructor;
  • PropertyChanged event
  • ShouldRaiseEvents protected boolean property
  • VerifyPropertyName() conditional method
  • BeginUpdate()/EndUpdate() method pair
  • Two protected methods OnPropertyChanged()
  • SetPropertyValue<T> generic helper method

Let's review these members.

The constructor

The constructor just sets the ShouldRaiseEvents property to true - a newly created NotifyingObject notifies it's subscribers about property changes.

PropertyChanged

This event is supposed to be raised when one or more properties change their values. This is the implementatio of the INotifyPropertyChanged interface.

ShouldRaiseEvents property

This protected property allows the inheriting code to enable/disable property change notifications or check if they are enabled. It is a good idea to check the state of this property in inheriting classes that add more events.

NB: At the moment the property is implemented as a simple bit flag. However, it migh be better to use a counter instead to allow nested bulk updates. This change might be introduced in the future but it will be a breaking change.

VerifyPropertyName() method

This conditional method checks if the inheriting class has a property with provided name. It may save the developer from typos.

The method is marked with [Conditional("DEBUG")] attribute and gets removed in release builds.

BeginUpdate()/EndUpdate() methods

These two virtual methods implement the IUpdatable interface and manipulate the value of the ShouldRaiseEvents property.

OnPropertyChanged() overloads

These two protected overloads raise the PropertyChanged event. The one that accepts a property name as a parameter is sealed, the other, that accepts an instance of the System.ComponentModel.PropertyChangedEventArgs class, is virtual. If you need to intercept the propety changed events in derived classes, override it but call the base implementation.

Here is an example of these methods use:

string key;

public string Key
{
    get
    {
        return key;
    }
    set
    {
        if(key != value)
        {
            key = value;
            OnPropertyChanged("Key");
        }
    }
}

SetPropertyValue<T>() method

This helper method has following signature:

protected bool SetPropertyValue<T>(ref T backingField, T newValue, [CallerMemberName] string propertyName = null)

The backingField is the reference to the field that contains the value of the proerty that has been changed. It's a ref parameter because backing fields may be value types that are passed by value. The newValue is, obviosely, the new value of the property. The propertyName is the name of the property that has been changed. The way this argument is declared allows the developer to ommit it, the compiler will generate the correct value automatically.

Here is an example of this method (a simplified previous example):

string key;

public string Key
{
    get
    {
        return key;
    }
    set
    {
        SetPropertyValue(ref key, value);
    }
}

You should stick to use this method. One clear exception would be a property that depends on the value of another property:

string firstName;

string lastName;

public string FirstName
{
    get
    {
        return firstName;
    }
    set
    {
        if(firstName != value)
        {
            firstName = value;
            OnPropertyChanged("FirstName");
            OnPropertyChanged("FullName");
        }
    }
}

public string LastName
{
    get
    {
        return firstName;
    }
    set
    {
        if(lastName != value)
        {
            lastName = value;
            OnPropertyChanged("LastName");
            OnPropertyChanged("FullName");
        }
    }
}

public string FullName
{
    get
    {
        return firstName + " " + lastName;
    }
}

NotifyingCollection class

This class is a base class for collections with notifications. It inherits from the NotifyingObject and implements the System.Collections.Specialized.INotifyCollectionChanged interface. In addition to the members of the NotifyingObject it defines or overrides the following methods:

  • A protected constructor
  • CheckReentrancy() protected method
  • CollectionChanged event
  • OnCollectionChanged() protected virtual method
  • OnPropertyChanged() protected overloaded method
  • IsReadOnly abstract property
  • CheckReadOnly() protected method

Let's review these members.

The constructor

The constructor initializes the object. The ShouldRaiseEvents property is set to true by the base class constructor.

CheckReentrancy() method

The collection cannot be modified when subscribers handle notifications. You should call the CheckReentrancy() method in any method that potentially modifies the collection. It throws the System.InvalidOperationException if the collection sends the notifications.

CollectionChanged

This complex event is raised when the collection is changed - items being added or removed. Thorougly read the documentation on this event when implementing your observable collections!

OnCollectionChanged() method

This method raises the CollectionChanged event. It sets an internal flag during this.

OnPropertyChanged() overloaded method

This method is overloaded to set the internal flag during the PropertyChanged event.

IsReadOnly property

This abstract property must be implemented by a derived class. It is checked by the CheckReadOnly() method.

CheckReadOnly() method

This method throws an InvalidOperationException if the collection is read-only and the user cannot modify it.

These two classes introduce rather flexible boilerplate code for WPF view models.


Related

Wiki: Home