Creating a strongly typed reactive wrapper to INotifyPropertyChanged

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.

WPF/E December CTP

The boys over at Microsoft have finally released a CTP of WPF/E. You can also download the client for both Windows and Mac

There is also a Learn WPF/E page up that acts as an intro FAQ, but then links off to the official WPF/E FAQ. Still, they did provide a nice browser compatibility matrix that shows that WPF/E supports IE/Firefox/Safari in Windows + Mac (except Firefox 2.0 on Mac, which will be supported by the next CTP).

WPF/E is a cross-platform / web subset of WPF, enabling XAML (an open specification) to be used in websites to create “rich experiences” (rich synergistic experiences?). The big draw is that you get to write in C#; Microsoft have created a cross-plaform mini-CLR.

Despite the similarities, Microsoft insist that they are not competing with Macromedia Flash, although I’m not sure how much I believe that.

XPath Test Utility

I’m working on a project that requires large XML documents and complex XPath queries. When I looked around online, I couldn’t find any decent .NET oriented XPath test utilities. And so, I wrote this.

XPathTest.exe is a command line utility lets you do the following:

  • Load XML Documents
  • Move the ‘current’ node to the first match of an XPath query
  • Display the results of an XPath query
  • Add custom XML namespace prefixes (although the namespaces from the document are extracted automatically)

It’s not perfect and it’s only a few hours work, but I find it useful. I’ll try to put the source code up as soon as I can.

Download XPathTest.exe (v0.1)

Looking at CardSpaces

I’ve started looking at CardSpaces. It’s pretty cool; it enables us to get rid of usernames/passwords without Microsoft owning your data (like passport). It’s a completely open standard that anyone can implement, and there are already examples in PHP and other non-Microsoft languages/platforms.

Basically an Identity Provider (eg. Google, Live ID, Commonwealth Bank, Government) can issue you a Card which claims a certain aspect of your identity. When a Relying Party (read: your website) needs to be sure of an aspect of the user’s identity, they ask for a card. Specifically, a list of required and optional “claims” (firstname/lastname/date of birth/favourite colour) is supplied, as well as the “token format” (the format in which the claims should be serialised). The information card selector (CardSpaces on Windows) then filters valid cards and allows the user to select one.

If the information is as simple as the user’s surname, the site will accept a self-issued (user created) card with that information. If self-issued is not good enough, say for proving the user’s age, the site may require a Managed Key. For example, a movie trailer rated MA or R can force you to supply a card that proves that you are over 15/18, which your government might supply to you when you reach that age.

The claims are specified using fully qualified names (ie. with namespaces). Microsoft have a created a few already for the obvious items (like the ones above), but you DONT have to use them. If you create your own firstname claim, like http://schemas.richardszalay.com/identity/2006/firstname, any identity providers would need to know about it. This is really only recommended if your company/website is the identity provider as well as the relying party.

Another case is a site can ask for your firstname/lastname/email address so that you can access the forums. If the card is self-issued, you are sent a confirmation email with a link to activate your email address. If the card is managed (like a Hotmail card), then this step is skipped because Hotmail is vouching for the valid email address. Cards re-validate with their Identity Provider when used, which means you can cancel a card and it will be unusable, just like a credit card.

I have mucked around with the implementation side of a relying party a little and I’ll post about it a bit later.