XAML Data Binding - Part 5
Last time, we looked at how to raise a PropertyChanged event, like this:
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler == null)
return;
handler(this, new PropertyChangedEventArgs(propertyName));
}
which is fine, but what about that magic string in the signature? We can certainly call this in the property's setter like RaisePropertyChanged("FirstName"), but what happens when the FirstName property gets renamed Forename? It's easy to forget to keep strings up to date, especially if there are plenty of them...
The scene is set for an alternative solution: Enter - Expressions.
An Expression is something that 'represents' a piece of code - it holds the code so that we can use it later if we need to. This allows us to access the information about the property, for example the Name which we need to pass into the PropertyChanged event.
So how do we get the Name out of the property? From the property setter we need to represent the property as a lambda expression, and pass that into a method that takes the lambda in as a parameter and uses it to extract the name. It looks like this:
public string FirstName
{
get { return _firstName; }
set
{
if (value == _firstName) return;
_firstName = value;
RaisePropertyChanged(() => FirstName);
}
}
protected static string RaisePropertyChanged<TProp>(this Expression<Func<TProp>> propertyExpression)
{
var handler = PropertyChanged;
// Check the event handler exists
if (handler == null) return;
var lambda = propertyExpression as LambdaExpression;
MemberExpression memberExpression;
// If the property is a value type, the Body will be a Unary expression
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
if (memberExpression == null)
throw new ArgumentException("propertyExpression does not represent a valid MemberExpression");
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("propertyExpression does not represent a valid public property");
// Raise the event by invoking the handler
handler(this, new PropertyChangedEventArgs(propInfo.Name));
}
And that's that. Now we have swapped
RaisePropertyChanged("FirstName");
for
RaisePropertyChanged(() => FirstName);
which is a good deal more refactor-proof than the magic-string version...


Comments
Ian Randall
Update: This post is showing you how to raise a
PropertyChangedevent from your property setter.This article from Brendan explains why you might not want to...