My ultimate INotifyPropertyChanged implementation

Standard
Share

In the Model-View-ViewModel design pattern, we make frequent use of the INotifyPropertyChanged interface. It is the Interface that defines the necessary methods to Notify the UI when a Property has Changed. As you can see, its a very well-named Interface. πŸ™‚

I’ve collected a few variations of the implementation and placed them all into a single ViewModelBase class. I didn’t write any of these myself – rather, I found them strewn about the internet. I’ve documented where I got some of them; others were (and probably still are) readily available from a multitude of sites. I’m making my collection available here, and I’ll give a few examples of how to use it. I’ll also explain the “evolution” my use of this interface has undergone.

To keep things organized, I usually create a folder named MVVM in my solution to house this class. You’ll want to update the namespace in this class to match your project; eventually I’m sure I’ll just compile it into a DLL once its evolution has ceased.

NotifyPropertyChanged(string PropertyName)

public class Person : MVVM.ViewModelBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if ( name != value )
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }
}

Here we have a simple Person class with a single string property called “Name”. Note that the class inherits from MVVM.ViewModelBase, which gives us access to the methods housed in that class. The “Name” property has get and set accessors, along with a private backing field called “name”. You can see in the set accessor of the “Name” property we’re simply:

  • Checking to see if the new “Name” value differs from the stored “name” value. This check will prevent the UI from updating any bound controls when “Name” is being set to its existing value, in which case no UI update is necessary (line #9)
  • Updating the “name” backing field with the new “Name” value. (line #11)
  • Calling the NotifyPropertyChanged(string PropertyName) method housed in the ViewModelBase class. (line #12)
  • The call to

    NotifyPropertyChanged("Name");
    

    notifies all UI controls that are bound to the “Name” property that the property value has changed, and therefore an update to the UI is required.

    The problem we run into is that this string parameter is in no way tied to the name of the property itself. That is to say, if we refactor the property and change the “Name” property to “PersonName”, the string passed to the NotifyPropertyChanged method doesn’t change accordingly. Instead, we’ll have to manually update every call from

    NotifyPropertyChanged("Name");
    

    to

    NotifyPropertyChanged("PersonName");
    

    This isn’t a big deal in a small class like the Person class example above, but you can imagine with much larger classes (that might have multiple instances of the NotifyPropertyChanged method invoked on the “Name” property) that it could become a problem. This led me to the second iteration of NotifyPropertyChanged:

    NotifyPropertyChanged<T>(Expression<Func<T>> expression)
    Repeating the example above, we’ll create a simple Person class. Only this time, we’ll issue a call to another overload of NotifyPropertyChanged.

    public class Person : MVVM.ViewModelBase
    {
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if ( name != value )
                {
                    name = value;
                    NotifyPropertyChanged(() => Name);
                }
            }
        }
    }
    

    Note the different parameter being passed to NotifyPropertyChanged (line #12). Instead of the name of the property as a string (“Name”), we’re passing a lambda expression that points to the class property “Name”. The end result is the same – UI controls bound to the “Name” property are notified when the “Name” value changes so they can update the UI. The difference here is that the lambda expression is referring to a property in the class. Renaming our property via refactor from “Name” to “PersonName” will now properly update the parameter in the call to NotifyPropertyChanged.

    NotifyPropertyChanged(() => Name);
    

    becomes

    NotifyPropertyChanged(() => PersonName);
    

    This is a significant improvement, as it removes any hard-coded strings in the code, and becomes friendly to changes via refactoring. However, it may seem redundant to keep passing a lambda expression that refers to the property calling the NotifyPropertyChanged. This is where the third overload of NotifyPropertyChanged comes into play:

    NotifyPropertyChanged()

    public class Person : MVVM.ViewModelBase
    {
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if ( name != value )
                {
                    name = value;
                    NotifyPropertyChanged();
                }
            }
        }
    }
    

    You’ll immediately note that this overload doesn’t take any parameters, so we don’t have any property renaming issues like we did with the first iteration. Instead, it uses the StackFrame.GetMethod method to determine which method called it, then simply passes this information to the first version described above as a string.

    I’ve stopped using NotifyPropertyChanged(string PropertyName) in my code, but it’s still used behind the scenes by NotifyPropertyChanged(). I keep NotifyPropertyChanged<T>(Expression<Func<T>> expression) in my NotifyPropertyChanged implementation for use outside of the property to be updated. Consider the following modified and expanded Person class:

    public class Person : MVVM.ViewModelBase
    {
        public string Name
        {
            get { return FirstName + " " + LastName; }
        }
    
        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set
            {
                if ( lastName != value )
                {
                    lastName = value;
                    NotifyPropertyChanged();
                    NotifyPropertyChanged(() => Name);
                }
            }
        }
    
        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                if ( firstName != value )
                {
                    firstName = value;
                    NotifyPropertyChanged();
                    NotifyPropertyChanged(() => Name);
                }
            }
        }
    }
    

    Here, we’ve added the properties “LastName” and “FirstName”, along with the appropriate backing fields (“lastName” and “firstName”, respectively) and get and set accessors. We’ve also included the necessary calls to NotifyPropertyChanged() in the set accessors.

    We’ve also modified the “Name” field to use only a get accessor, as its value is built from the “FirstName” and “LastName” field values. However, because its value is being built from the “FirstName” and “LastName” field values, we need to call

    NotifyPropertyChanged(() => Name);
    
    NotifyPropertyChanged(() => Name);
    

    anytime the “FirstName” or “LastName” fields are updated.

    My collection of NotifyPropertyChanged methods can be downloaded here.

One thought on “My ultimate INotifyPropertyChanged implementation

Leave a Reply

Your email address will not be published. Required fields are marked *