All XAML developers are well aware of INotifyPropertyChanged interface. This interface is key to the data binding. Every ViewModel class or ViewModelBase abstract class implements this interface. One of the biggest issue with it is that the PropertyChangedEventHandler delegate event argument, PropertyChangedEventArgs constructor accepts the property name as string value. This can introduce bug in your code because of “MAGIC STRINGS” , where by which if developer misspell the property name or you require to rename your property , then it should be done very carefully otherwise your data binding can go completely for a toss and you would go in circles to figure out what the issue is. Let me illustrate what I am talking about with the code snippet below.
- public class CustomerViewModel : INotifyPropertyChanged
- {
- private string customerNameValue = String.Empty;
- private string phoneNumberValue = String.Empty;
- public event PropertyChangedEventHandler PropertyChanged;
- private void NotifyPropertyChanged(String propertyName)
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- public string CustomerName
- {
- get
- {
- return this.customerNameValue;
- }
- set
- {
- if (value != this.customerNameValue)
- {
- this.customerNameValue = value;
- NotifyPropertyChanged("CustomerName"); //Magic strings
- }
- }
- }
- public string PhoneNumber
- {
- get
- {
- return this.phoneNumberValue;
- }
- set
- {
- if (value != this.phoneNumberValue)
- {
- this.phoneNumberValue = value;
- NotifyPropertyChanged("PhoneNumber"); //Magic strings
- }
- }
- }
- }
In this short post I will talk about how you can avoid using these magic strings by using one of C# new 5.0 feature named as CallerMemberName attribute with support of optional parameters. So let us do some code refactoring in the above code and remove these magic strings. Have a look at the code snippet below.
- public class CustomerViewModel : INotifyPropertyChanged
- {
- // These fields hold the values for the public properties.
- private string customerNameValue = String.Empty;
- private string phoneNumberValue = String.Empty;
- public event PropertyChangedEventHandler PropertyChanged;
- private void NotifyPropertyChanged([CallerMemberName]
- String propertyName = "")
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- public string CustomerName
- {
- get
- {
- return this.customerNameValue;
- }
- set
- {
- if (value != this.customerNameValue)
- {
- this.customerNameValue = value;
- NotifyPropertyChanged(); //Look ma no magic strings
- }
- }
- }
- public string PhoneNumber
- {
- get
- {
- return this.phoneNumberValue;
- }
- set
- {
- if (value != this.phoneNumberValue)
- {
- this.phoneNumberValue = value;
- NotifyPropertyChanged(); //Look ma no magic strings
- }
- }
- }
- }
Just have a look at NotifyPropertyChanged method in the above code snippet. This method argument is decorated with CallerMemberName attribute. This will replace the property name in the set accessor of that property. So you don’t need to hardcode any property name.
On the closing note I would also like to say that this is not the only way you can avoid the MAGIC STRINGS in the method name. If you are fan of functional programming like me
and have some knowledge of generics you can use Linq Expressions to achieve the same. Let us see one more code snippet which does this.
- public class CustomerViewModel : INotifyPropertyChanged
- {
- // These fields hold the values for the public properties.
- private string customerNameValue = String.Empty;
- private string phoneNumberValue = String.Empty;
- public event PropertyChangedEventHandler PropertyChanged;
- private void NotifyPropertyChanged<T>(Expression<Func<T>> expression)
- {
- var lambda = (LambdaExpression)expression;
- MemberExpression memberExpr;
- var body = lambda.Body as UnaryExpression;
- if (body != null)
- {
- var unaryExpr = body;
- memberExpr = (MemberExpression)unaryExpr.Operand;
- }
- else
- {
- memberExpr = (MemberExpression)lambda.Body;
- }
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(memberExpr.Member.Name));
- }
- }
- public string CustomerName
- {
- get
- {
- return this.customerNameValue;
- }
- set
- {
- if (value != this.customerNameValue)
- {
- this.customerNameValue = value;
- NotifyPropertyChanged(() => CustomerName);
- }
- }
- }
- public string PhoneNumber
- {
- get
- {
- return this.phoneNumberValue;
- }
- set
- {
- if (value != this.phoneNumberValue)
- {
- this.phoneNumberValue = value;
- NotifyPropertyChanged(() => PhoneNumber);
- }
- }
- }
- }
As seen this is also cool way of avoiding the magic strings by using linq expressions. Finally a quick tip always create the base class (ViewModelBase) and encapsulate all the required functionalities in it. Then all your viewmodel classes must inherit this ViewModelBase class.
Hope you must have found this post useful. Please leave your valuable feedback in the comments section.



Reblogged this on dotNuts.
Comment by dotnuts — February 4, 2013 @ 4:43 am |