When creating a class that can be used with data binding, you have to implement the INotifyPropertyChanged interface.  This interface requires that you have an event for PropertyChanged, specifying PropertyChangedEventArgs that provide the property name that was changed.

Here’s what I mean:

   1: public class Person : System.ComponentModel.INotifyPropertyChanged
   2: {
   3:     private string _name;
   4:  
   5:     public string Name
   6:     {
   7:         get { return _name; }
   8:         set
   9:         {
  10:             if (value != _name)
  11:             {
  12:                 _name = value;
  13:  
  14:                 if (this.PropertyChanged != null)
  15:                     this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Name"));
  16:             }
  17:         }
  18:     }
  19:  
  20:     #region INotifyPropertyChanged Members
  21:  
  22:     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
  23:  
  24:     #endregion
  25: }


Most of the time when you’re implementing this interface, you end up creating a method that will raise the event, yielding this code:

   1: public class Person : System.ComponentModel.INotifyPropertyChanged
   2: {
   3:     private string _name;
   4:  
   5:     public string Name
   6:     {
   7:         get { return _name; }
   8:         set
   9:         {
  10:             if (value != _name)
  11:             {
  12:                 _name = value;
  13:                 this.RaisePropertyChanged("Name");
  14:             }
  15:         }
  16:     }
  17:  
  18:     private void RaisePropertyChanged(string propertyName)
  19:     {
  20:         System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(propertyName));
  21:         this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
  22:     }
  23:  
  24:     #region INotifyPropertyChanged Members
  25:  
  26:     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
  27:  
  28:     #endregion
  29: }


But every time I write code like that, I shudder at having to put the property name in quotes.  I despise hard-coded strings like this because if I later decide to change the name of the property to FirstName, nothing will tell me that I’m no longer informing the UI of property changes.  What I’d really like is to create a RaisePropertyChanged method that accepts no parameters.  Instead of the property name parameter, it uses the StackFrame class to determine what property setter made the call and then it raises the event appropriately.

Here’s what I came up with:

   1: private void RaisePropertyChanged(string propertyName)
   2: {
   3:     System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(propertyName));
   4:     this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
   5: }
   6:  
   7: private void RaisePropertyChanged()
   8: {
   9:     string caller = new System.Diagnostics.StackFrame(1, false).GetMethod().Name;
  10:  
  11:     if (caller.StartsWith("get_") || caller.StartsWith("set_"))
  12:     {
  13:         caller = caller.Substring(4);
  14:     }
  15:  
  16:     this.RaisePropertyChanged(caller);
  17: }


This works really well in WPF, but it doesn’t work in Silverlight.  Why?  Because the Silverlight runtime applies a SecurityCriticalAttribute to the StackFrame class, restricting its use to the Silverlight framework.  Understandable, but that means I cannot pull off RaisePropertyChanged() inside a Silverlight application.  Hard-coded strings it is.

Technorati Tags: ,,