Type-Safe Two-Way Data Binding with INotifyPropertyChanged

Anyone who’s developed a UI application using Windows Forms, WPF or Silverlight is probably aware that you have to implement the INotifyPropertyChanged interface to get two-way data binding between UI elements and an underlying data source. The problem is that you have to pass the name of the property as a string when you fire the event from each property setter. In this post I will show you a better way, namely, how you can use lambda expressions instead of strings to pass the property name.  That way, the compiler will check that the property name matches a valid property on the class, which will prevent your data bindings from breaking should you change a property name on your class and forget to update the property changed argument.  My Simple MVVM Toolkit provides base classes that include convenient helper methods for firing the PropertyChanged event in a type-safe manner.  You can download the code for this blog post here.

For example, let’s say you have a Person class with Name and Age properties.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

And you want to bind it to a XAML page that has two textboxes.

<Grid x:Name="LayoutRoot" Background="White"
        Height="150" Width="300">
    <Grid.DataContext>
        <my:Person Name="John" Age="20"
            xmlns:my="clr-namespace:TypeSafeTwoWayDataBinding"/>
    </Grid.DataContext>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <sdk:Label Content="Name:" />
    <sdk:Label Content="Age:" Grid.Row="1"/>
        
    <TextBox Grid.Column="1" Height="30" 
                Text="{Binding Path=Name, Mode=TwoWay}"/>
    <TextBox Grid.Column="1" Grid.Row="1" Height="30" 
                Text="{Binding Path=Age, Mode=TwoWay}"/>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
                Grid.Row="2" Grid.ColumnSpan="2">
        <Button Name="showPersonButton" Margin="5"
            Height="30" Width="100" Content="Show Person" 
            Click="showPersonButton_Click" />
        <Button Name="birthdayButton" Margin="5"
            Height="30" Width="100" Content="Birthday" 
            Click="birthdayButton_Click" />
    </StackPanel>
</Grid>

The XAML looks like this in the Visual Studio designer:

person-page_thumb11

In the button click of “Show Person” you display a message box with Person Name and Age, and in the click of “Birthday” you increment Person Age.

private void showPersonButton_Click(object sender, RoutedEventArgs e)
{
    Person person = (Person)LayoutRoot.DataContext;
    MessageBox.Show(person.Name + " " + person.Age);
}

private void birthdayButton_Click(object sender, RoutedEventArgs e)
{
    Person person = (Person)LayoutRoot.DataContext;
    person.Age++;
}

If you were to run the app and click the Birthday button you would not see the value in the Age textbox increase, even though clicking the Show Person button reveals that the age has indeed increased. The reason for this is that Person needs to inform the binding that the Age property has changed so that it can get the new value.  This is accomplished by implementing INotifyPropertyChanged on Person and firing the PropertyChanged event in each property setter.

public class Person_Bad : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            if (PropertyChanged != null)
                PropertyChanged(this,
                    new PropertyChangedEventArgs("Name"));
        }
    }

    private int age;

    public int Age
    {
        get { return age; }
        set
        {
            age = value;
            if (PropertyChanged != null)
                PropertyChanged(this,
                    new PropertyChangedEventArgs("Age"));
        }
    }
}

As you can see, this requires a lot of repetitive code and the use of strings is error-prone. If you were to change the property name and forget to update the string, the bindings would break without even the benefit of a runtime exception. To solve this, it’s possible to write a helper method that accepts a lambda expression instead of a string.  When a lambda is assigned to an Expression<T> the compiler generates an expression tree instead of a delegate.  Expression trees are simply a representation of code as data, usually in order to transform it to something else.  In this case that something else would just be the name of the property. A convenience place for this helper method is in a base class, which can also check to make sure the PropertyChanged event is not null.

public class ModelBase<TModel> : INotifyPropertyChanged
{
    // Allows you to specify a lambda for notify property changed
    public event PropertyChangedEventHandler PropertyChanged;

    // Defined as virtual so you can override if you wish
    protected virtual void NotifyPropertyChanged<TResult>
        (Expression<Func<TModel, TResult>> property)
    {
        // Convert expression to a property name
        string propertyName = ((MemberExpression)property.
            Body).Member.Name;

        // Fire notify property changed event
        InternalNotifyPropertyChanged(propertyName);
    }

    protected void InternalNotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

We can then refactor our Person class to call NotifyPropertyChanged in each property setter. The really nice thing about this is that the compiler is smart enough to infer TModel and TResult type arguments, which makes the code much cleaner.

public class Person : ModelBase<Person>
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyPropertyChanged(m => m.Name);
        }
    }

    private int age;
    public int Age
    {
        get { return age; }
        set
        {
            age = value;
            NotifyPropertyChanged(m => m.Age);
        }
    }
}

Lastly, the toolkit also comes with a code snippet that inserts the property code and includes the call to NotifyPropertyChanged.  So all you have to do is type mvvmprop, then hit the tab key to expand the snippet.  Then just type content for each field as you tab through the snippet replacements for the property type, field name, property name, and lambda parameter name.

mvvmprop-before_thumb3

mvvmprop-after_thumb3

You now have properties that fire PropertyChanged in a type-safe manner for robust two-way data binding on your model classes.  The toolkit provides this support for view-models as well.  In a prior post I also described an AssociateProperties method that will link property notifications for two properties together, for example, a property in the view-model that is dependent on one or more properties in the model.  In a future post I’ll discuss the asynchronous support provided by the toolkit, which ensures that PropertyChanged always fires on the UI thread if you are updating properties or firing notification events from a background task running on a worker thread.

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged , . Bookmark the permalink.

13 Responses to Type-Safe Two-Way Data Binding with INotifyPropertyChanged

  1. jordan says:

    nice article. makes INotifyPropertyChange a lot “safer” to use 🙂
    thanks.

  2. Siddharth says:

    Hi,

    I am new to MVVM pattern using with Silverlight.
    I am using INotifyPropertyChange and in the GridView i am Binding to the Itemsource with TwoWay mode but it is not showing the Grid with the Updated Values.
    Can u please help me regarding this,

    Thanks in Advance,
    Siddharth

  3. sdsdsd says:

    good
    explanation given
    thank you very much

  4. Deepak says:

    Awesome Tony..Even Though I am starter in silver light,I feel its a walk through…Thanks a lot..Keep up the good work

  5. pirimoglu says:

    thanks for article. How about performance for this implementation? I found an article about this problem told. http://tsells.wordpress.com/2011/02/08/using-reflection-with-wpf-and-the-inotifypropertychanged-interface (at the end of article)

  6. Hitchs says:

    Hi Tony,
    That is a great post!
    Hi,

    I have a silverlight usercontrol which displays a viewmodel on a grid from a source list which contain two coulmns in that list (Item(string), Checked(bool))

    This “checked” is binding to a image, which turns into green colored image when I click on it and store the vaue as “1” in the list and to red, value to “0”, when I click again.

    Now When the value is changed in the list, I want to reflect on the grid also at the same time. that means when the “checked” value is set to “1” in the list, it should update the viewmodel to Greenimage at the same time with out refreshing it. Through my searching I found INotifyPropertyChaned is an option for me.

    I have class as
    ListClass Public class List
    { Public string Item{get; set;}
    public bool Checked{get; set;}
    }

    Now I want this onpropertychanged to fire on “Checked”. and I got another Xaml, xaml.cs file.

    Can you please help me how can I do that for this application?

    • Tony Sneed says:

      You need my Simple Mvvm Toolkit! To get it, just open Visual Studio, select Tools, Extensions, then search for it. After downloading and installing the toolkit, view the Getting Started video and go through the sample code.

      With regard to your specific question, you will create a ViewModel using the toolkit template, then bind a View to it. Based on the checked value, your binding will show the desire UI element.

      Feel free to follow up by posting to the discussion forum on the toolkit codeplex site.

      Cheers,
      Tony

  7. Michael says:

    Very nice. Didn’t know about MemberExpression way of doing it. Interesting use of generics in the base class. That makes for super easy access to the name. I usually end up with a similar helper pattern going on, involving the setter helper, a SetProperty(ref TResult field, TResult value, Func TResult, TResult, bool changing, Expression Func TModel, TResult property, …) type of approach. Usually generically enough that can bridge into whatever Mvvm framework, regardless whether Xaml-based (i.e. Silverlight, Wpf) or Winforms-based. The Mvvm pattern remains the same. View-model rarely becomes necessary, and is simply an extension of the model-base, knows how to notify itself, can be used to expose models into views that need more than just the model. Example, property grids that only needs to expose certain properties, not all, can be done that way, or grid or list views or whatever.

    • Michael W Powell says:

      Been a little while, but yes; well aware. There’s been a lot of changes since I posted this, some pretty good, tuples, NAMEOF (they really did a good thing with that one, IMO), etc. Some not so good, downright confusing, I think, i.e. “null reference types”. But, yes; well, well, aware, use it all the time, and perhaps in ways they did not even envision at the get go.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.