Properties with property changed event, part 2

Last time I talked about properties with a changed event, I described the traditional pattern of having one event per property. But there is a disadvantage to that approach: since an event needs storage for a delegate, this technique wastes a considerable amount of memory if nobody subscribes to the events.

Say you have 10 properties of reference types with a simple backing variable each. On a 32 bit machine, those will take 40 bytes plus the storage of the actual objects (if any). If each of these properties has an associated event, that's 40 additional bytes (plus storage for the delegate objects, if any).

If you want to monitor if anything changes to the object, no matter which property it is that actually changes, you need to subscribe to all 10 events, and that's going to create 10 delegate objects.

The System.ComponentModel.INotifyPropertyChanged interface provides an interesting alternative. It declares just one event:

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

A PropertyChangedEventHandler is an event handler that takes an object (sender) and  a PropertyChangedEventArgs, an EventArgs with an additional string PropertyName property.

How do we use this interface? Say I have a class Customer with two string properties: Name and City. It would look like this:

using System;
using System.ComponentModel;

class Customer : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }

    private string name;

    public string Name
    {
        get { return name; }
        set
        {
            if (value != name)
            {
                name = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Name"));
            }
        }
    }

    private string city;

    public string City
    {
        get { return city; }
        set
        {
            if (value != city)
            {
                city = value;
                OnPropertyChanged(new PropertyChangedEventArgs("City"));
            }
        }
    }
}

Even though there are two properties, there is only one event. The advantages: less code, less memory usage. There are disadvantages as well though. If you're interested only in changes to the Name property, your event handler needs to test the PropertyName in the PropertyChangedEventArgs passed to you. And you may get a lot of calls notifying you of changes to properties your aren't interested in. On the sending side, be careful with rename refactorings, since the strings being passed around won't be refactored by Visual Studio.

Nevertheless, this approach is becoming the dominant technique for data binding scenarios. In fact, the new Linq to SQL generated classes use this approach as well. So you might just as well get accustomed to it.

In part 3 of this series, we'll have a look at how Windows Forms controls store their event delegates, with a CueBannerTextBox example.