PresentationModel – Strongly Typed Implementation of INotifyPropertyChanged

I’ve posted about the PresentationModel pattern when creating user interfaces.  The implementation of the model in the previous post did not fully utilize the binding model of Silverlight (or WPF).  An example of the previous implementation is below.

 public class MyModel : IMyModel
 {
     public int SomeIntValue { get; set; }

     public string SomeStringValue { get; set; }
 }

The above model works fine when set to the DataContext of your view (form) and the controls are bound to those values. The problem comes in when you want to change the value of one of these properties. If I were to change the integer in the above model, any controls that are bound to that property would not be updated because they have no way to know that model behind the scenes changed. One possible workaround would be to rebind the model to the DataContext of the form but this would be a huge performance hit with a model that contains a large number of properties. The ideal solution would be to notify the view that a single property has changed and each control that is bound to that property needs to re-pull the value from the model. In comes the INotifyPropertyChangedInterface! Unfortunately, using this interface prehibits the use of auto-implemented properties so you’ll have to introduce backing fields. Not a huge deal though. New implementation is below.

 public class MyModel : IMyModel, INotifyPropertyChanged 
 {
     private int someIntValue;
     private string someStringValue;

     public event PropertyChangedEventHandler PropertyChanged;

     public int SomeIntValue
     {
         get
         {
             return someIntValue;
         }
         set
         {
             someIntValue = value;
             PropertyChanged(this,
                 new PropertyChangedEventArgs("SomeIntValue"));
         }
     }

     public string SomeStringValue
     {
         get
         {
             return someStringValue;
         }
         set
         {
             someStringValue = value;
             PropertyChanged(this,
                 new PropertyChangedEventArgs("SomeStringValue"));
         }
     }
 }
 

Now, whenever the value of property is changed on the model, any controls that are bound will be updated in the view! But we can do better. Notice we’re passing a string when the PropertyChanged event is fired to indicate what property has been updated. It would be nice to do this in a strongly typed fashion to ensure we didn’t misspell the property name and if you’re a fan of resharper, performing a Rename, will automatically change the property in all places it’s referenced, something that won’t happen if it’s referenced as a string.

Luckily, Linq can help us here. I’m going to do two things in the next implementation. 1) The logic will be abstracted to a base model class so it can be reused in each model implementation. 2) Using Linq, we can reference the property in a strongly typed way to remove any chance of a misspelling and leave us confused as to why a bound control is not getting updated.

 public class PresentationModelBase<T> : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler PropertyChanged;

     /* T is the type of our model
      * TValue is the type of the property that is being referenced,
      * not really important at this point but still needed.
      */
     protected void FirePropertyChanged<TValue>(
         Expression<Func<T, TValue>> property)
     {
         if (PropertyChanged == null)
         {
             return;
         }

         MemberExpression memberExpression =
             property.Body as MemberExpression;
         if (memberExpression != null)
         {
             PropertyChanged(this,
                 new PropertyChangedEventArgs(
                     memberExpression.Member.Name));
         }
     }
 }
 

What Linq is allowing us to do here is to take a lambda expression (can see below in impl. of the model) and represent it in a data structure that we can inspect to go after the metadata that it holds. The piece of metadata we’re most interested in is the name of the property that is being referenced (ie memberExpression.Member.Name).

And the updated model.

 public class MyModel : PresentationModelBase<MyModel>, IMyModel
 {
     private int someIntValue;
     private string someStringValue;

     public int SomeIntValue
     {
         get
         {
             return someIntValue;
         }
         set
         {
             someIntValue = value;
             FirePropertyChanged(p => p.SomeIntValue);
         }
     }

     public string SomeStringValue
     {
         get
         {
             return someStringValue;
         }
         set
         {
             someStringValue = value;
             FirePropertyChanged(p => p.SomeStringValue);
         }
     }
 }
Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s