Simplified UWP View Mode Base

If you’ve implemented a ViewModelBase (or some object that implements INotifyPropertyChanged) in UWP there’s a pattern that you will recognize. When a property value is being set you might check to see if the new value is different from the previous value, if it is then you assign the value to the property and call the OnPropertyChanged event. Such code might look something like this.

public abstract class ViewModelBase: INotifyPropertyChanged {
   public event PropertyChangedEventHandler PropertyChanged;
   protected OnPropertyChanged(String propertyName)
   {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
}

public class Employee : ViewModelBase{
   private int _employeeID; 
   public int EmployeeID
   {
      get { return _employeeID; }
      set 
      {
         if(_employeeID != value )
         {
            _employeeID = value;
            OnPropertyChanged("EmployeeID")
         }
      }
   }
}

While it works it could be better. The first improvement is in the implementation of OnPropertyChanged. If someone my a typo in the name of the property it might not noticed until runtime debugging (if at all). It would be better if such an error were caught at compile time. There’s a different implementation of OnPropertyChanged that can do this.

protected void OnPropertyChanged(Expression expression)
{
   OnPropertyChanged(((MemberExpression)expression.Body).Member.Name);        
}

With this implementation instead of typing the name of the property we can type an expression for the property. If we make a mistake in the expression it will cause a compile time error. Out Employee class will now look like the following.

public class Employee : ViewModelBase{
   private int _employeeID; 
   public int EmployeeID
   {
      get { return _employeeID; }
      set 
      {
         if(_employeeID != value )
         {
            _employeeID = value;
            OnPropertyChanged(()=>EmployeeID)
         }
      }
   }
}

That’s improved, but there’s still room for improvement. Checking for the value to be different and then conditionally assigning the value can be modularlized so that we don’t have to keep typing it. To do this I add a couple of additional methods to the ViewModelBase.

protected bool SetValueIfChanged(Expression<Func> propertyExpression, Expression<Func> fieldExpression, object value)
{
    var property = (PropertyInfo)((MemberExpression)propertyExpression.Body).Member;
    var field = (FieldInfo)((MemberExpression)fieldExpression.Body).Member;
    return SetValueIfChanged(property,field, value);
}

protected bool SetValueIfChanged(PropertyInfo pi,FieldInfo fi, object value)
{
    var currentValue = pi.GetValue(this);
    if ((currentValue == null && value == null)||(currentValue!=null &&  currentValue.Equals(value)))
        return false;
    fi.SetValue(this, value);
    OnPropertyChanged(pi.Name);
    return true;
}

The second version of this method is probably easier to understand. It uses classes from the reflection namespace to interact with the object. This allows it to operate on on any properties or fields as long as the reflection data is passed. The first implementation of this method takes an expression and gets the reflection data from it. Applying this to the Employee class it now looks like the following.

public class Employee : ViewModelBase{
   private int _employeeID; 
   public int EmployeeID
   {
      get { return _employeeID; }
      set { SetValueIfChanged(()=>EmployeeID, ()=>_employeeID, value); }
   }
}

Much better. Now if I want to reduce my typing even more instead of naming the method SetValueIfChanged I could name it something much shorter. One must still define the the fields that backup these properties. Rather than typing them out a code snippet could be defined for this pattern. A code snippet is like a template that is associated with a keystroke. I’ll talk about that in another post.

2 thoughts on “Simplified UWP View Mode Base

Leave a comment

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