I just finished a session on MVVM at DevReach in Sofia, Bulgaria and the concern came up about using a method to call the PropertyChanged event with a string for the property. Obviously this does not have compile-time safety and opens the door to a lot risk. In the real world, I use the Prism framework which has a facility to extract a property name from an expression so I pulled that piece out and am showing it here for those interest.
Here’s a very simple base class that encapsulates property change notification. Notice the overloaded method for raising the event. One uses a string argument and the other an expression.
1: public abstract class ObjectBase : INotifyPropertyChanged
2: {
3: public event PropertyChangedEventHandler PropertyChanged;
4:
5: protected internal void OnPropertyChanged(string propertyName)
6: {
7: if (this.PropertyChanged != null)
8: this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
9: }
10:
11: protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
12: {
13: var propertyName = ExtractPropertyName(propertyExpression);
14: OnPropertyChanged(propertyName);
15: }
16:
17: static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
18: {
19: if (propertyExpression == null)
20: {
21: throw new ArgumentNullException("propertyExpression");
22: }
23:
24: var memberExpression = propertyExpression.Body as MemberExpression;
25: if (memberExpression == null)
26: throw new Exception();
27:
28: var property = memberExpression.Member as PropertyInfo;
29: if (property == null)
30: if (memberExpression == null)
31: throw new Exception();
32:
33: var getMethod = property.GetGetMethod(true);
34: if (getMethod.IsStatic)
35: if (memberExpression == null)
36: throw new Exception();
37:
38: return memberExpression.Member.Name;
39: }
40: }
Using this is easy. Instead of sending in the property name as a string when calling OnPropertyChanged, you use an expression and get full compile-time safety:
1: public ViewModelBase CurrentChild
2: {
3: get { return _CurrentChild; }
4: set
5: {
6: if (_CurrentChild != null && _CurrentChild.Equals(value))
7: return;
8:
9: _CurrentChild = value;
10: OnPropertyChanged(() => CurrentChild);
11: }
12: }
Until next time…