INotifyPropertyChanged has been around forever, and so has the nasty string based property names that are passed to raise the events. Its all familiar stuff:
class Program
{
static void Main(string[] args)
{
var streamingPricesService = new StreamingPricesService();
Expression<Action<Object, PropertyChangedEventArgs>> test = (o, e) => Console.WriteLine("Property '{0}' changed ", e.PropertyName);
streamingPricesService.PropertyChanged
+= (o, e) => Console.WriteLine("Property '{0}' changed ", e.PropertyName);
streamingPricesService.PropertyChanged
+= (o, e) => Console.WriteLine("Property '{0}' changed ", e.PropertyName);
streamingPricesService.IsOnline = true;
Console.ReadKey();
}
private class StreamingPricesService : INotifyPropertyChanged
{
private bool _isOnline;
public bool IsOnline
{
get { return _isOnline; }
set
{
if (_isOnline != value)
{
_isOnline = value;
InvokePropertyChanged("IsOnline");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void InvokePropertyChanged(string propertyName)
{
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null) changed(this, new PropertyChangedEventArgs(propertyName));
}
}
}
..and its nasty!!
Enter Lambda LambdaExpression, its been around the block by now, you’ve all seen them, the PropertyChanged wireup below uses the meta data it exposes above, its type-safe and IMO cleaner. You can wrap the functionality up anyway you like, typically I’d put the INotifyPropertyChanged functionality in a class called NotifyingBase and keep the PropertyHelper in a separate class as its usually used in other situations too (however below its just all in 2 classes).
using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
var streamingPricesService = new StreamingPricesService();
streamingPricesService.PropertyChanged += (o, e) => Console.WriteLine("Property '{0}' changed ", e.PropertyName);
streamingPricesService.PropertyChanged += (o, e) => Console.WriteLine("Property '{0}' changed ", e.PropertyName);
streamingPricesService.IsOnline = true;
Console.ReadKey();
}
private class StreamingPricesService : INotifyPropertyChanged
{
private bool _isOnline;
public bool IsOnline
{
get { return _isOnline; }
set
{
if (_isOnline != value)
{
_isOnline = value;
InvokePropertyChanged(() => IsOnline);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void InvokePropertyChanged<T>(Expression<Func<T>> expression)
{
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null)
{
var propertyName = PropertyHelper.GetPropertyName(expression);
changed(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
public class PropertyHelper
{
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
return GetPropertyNameFromLambda(expression);
}
public static string GetPropertyName<T>(Expression<Func<T, Object>> expression)
{
return GetPropertyNameFromLambda(expression);
}
private static string GetPropertyNameFromLambda(LambdaExpression lambda)
{
MemberExpression memberExpression;
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(String.Format("Property expression '{0}' did not provide a property name.", lambda));
return memberExpression.Member.Name;
}
}
}