Practical Ugliness

INotifyPropertyChanged is a great, built-in, way for property change notification to work in the WPF/Silverlight world. Attempting to use it from staticly typed code, however, gets messy:

SomeViewModel viewModel;

viewModel.PropertyChanged += (s,e) =>
{
    if (e.PropertyName == "TheProperty")
        GetToWork(viewModel.TheProperty);
};

Things get even worse when we try to make this reactive:

var propertyChangedEvents = Observable.FromEvent(
    h => new PropertyChangedEventHandler(h),
    h => viewModel.PropertyChanged += h,
    h => viewModel.PropertyChanged -= h);

propertyChangedEvents
    .Where(x => x.PropertyName == "TheProperty")
    .Select(x => viewModel.TheProperty)
    .Subscribe(GetToWork);

An Expressive Solution

The extension method below allows you to specify the property you want to watch using an Expression<Func>, keeping things nice for the compiler:

Edit: Updated once it was tested (and simplified)

public static class NotifyPropertyChangeReactiveExtensions
{
    // Returns the values of property (an Expression) as they change,
    // starting with the current value
    public static IObservable<TValue> GetPropertyValues<TSource, TValue>(
        this TSource source, Expression<Func<TSource, TValue>> property)
        where TSource : INotifyPropertyChanged
    {
        MemberExpression memberExpression = property.Body as MemberExpression;
        if (memberExpression == null)
        {
            throw new ArgumentException(
                "property must directly access a property of the source");
        }
        string propertyName = memberExpression.Member.Name;
        Func<TSource, TValue> accessor = property.Compile();
        return source.GetPropertyChangedEvents()
            .Where(x => x.EventArgs.PropertyName == propertyName)
            .Select(x => accessor(source))
            .StartWith(accessor(source));
    }
    // This is a wrapper around FromEvent(PropertyChanged)
    public static IObservable<IEvent<PropertyChangedEventArgs>>
        GetPropertyChangedEvents(this INotifyPropertyChanged source)
    {
        return Observable.FromEvent<PropertyChangedEventHandler,
            PropertyChangedEventArgs>(
            h => new PropertyChangedEventHandler(h),
            h => source.PropertyChanged += h,
            h => source.PropertyChanged -= h);
    }
}

GetPropertyValues returns an IObservable of the values of the property as they change, starting with the current value.

You can then use it like so:

viewModel.GetPropertyChangeValues(x => x.TheProperty)
    .Subscribe(GetToWork);

I hope this method can be as useful to you as it has been to me.