Wednesday, March 17, 2010

A Smarter ViewModelBase

The advent of WPF has led to ubiquity of the MVVM pattern. Developers usually have a ViewModelBase class the implements the INotifyPropertyChanged interface as shown below:-

class ViewModelBase : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

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

The NotifyPropertChanged method is called from within the "set accessor" of a property with the name of the property passed as a parameter.

The problem with this implementation is that if the property name "string" parameter has be be in sync with actual property name as an when it changes. We as developers are prone to spelling mistakes and could easily leave out some property change notifications out of sync with the property name.

The following code address the problem mentioned above

class ViewModelBase : INotifyPropertyChanged
{
   private const string SetPropertyPrefix = "set_";

   #region INotifyPropertyChanged Members

   public event PropertyChangedEventHandler PropertyChanged;

   #endregion

   // Call this method from within a set accessor of a property
   protected void NotifyCurrentPropertyChanged()
   {
      if (PropertyChanged == null)
      {
         return;
      }

      StackTrace st = new StackTrace(1);
      StackFrame sf = st.GetFrame(0);
      MethodBase mb = sf.GetMethod();

      if (mb.MemberType == MemberTypes.Property)
      {
         // if the calling method is not an accessor of a property, do nothing
         string methodName = mb.Name;
         if (methodName.StartsWith(ViewModelBase.SetPropertyPrefix))
         {
            // We are bothered only with set accessors
            string propertyName = methodName.Substring(ViewModelBase.SetPropertyPrefix.Length);
            NotifyPropertyChanged(propertyName);
         }
      }
   }

   // The conventional NotifyPropertyChanged
   protected void NotifyPropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

The NotifyCurrentPropertyChanged method can be used in the set accessors of properties. Note that there is no need to pass the propery name anymore!

No comments:

Post a Comment