A lot of people have been talking about the Reactive Extensions for .NET, a flash new library from Devlabs which lets you do LINQ to .NET events just like you can with collections. My team at work has started using it pretty heavily, and today I wrote an adapter that allows you to use Rx over events published on the event aggregator in a Prism/Composite WPF application.

Here’s an example of using it in an imaginary chat client, to filter incoming messages from a particular person:

public class ConversationViewModel : IDisposable
{
    public IContact Friend { get; private set; }
    public ObservableCollection<IMessage> Messages { get; private set; }

    public ConversationViewModel(IContact friend,
        IEventAggregator eventAggregator)
    {
        // Interested only in messages sent by the person we are talking to.
        var messageReceivedEvents = eventAggregator
            .GetEvent<MessageReceived>()
            .AsObservable()
            .Where(msg => msg.Sender.Equals(Friend));

        eventSubscription = messageReceivedEvents.Connect();

        messageReceivedEvents.Subscribe(msg => Messages.Add(msg));
    }

    // We will keep receiving messages until the subscription is disposed.
    IDisposable eventSubscription;
}

It was a good exercise that helped me understand a bit more about how Rx works, and illustrates how easy it is to integrate with callback-based event systems (e.g. your favourite message bus).

You can grab the code here: CompositePresentationEventExtensions.cs

Update Jun 16 2010: Added finalizer to CompositePresentationEventSubscription.

March 30th, 2010 | 4 Comments

Last week, I encountered a problem doing some fiddly UI behaviour in a Prism/MVVM app. I wanted something like this:

I wanted a ComboBox where you can choose one of the available options, or none of them. Null, deselected, whatever.

Unfortunately for me, WPF doesn’t support binding null values in ComboBoxes, ListBoxes or ListViews. Now this is a pretty common problem, and a quick google reveals a few solutions available to this problem:

However, if like us, your domain model is all nicely decoupled through interfaces, the easiest way to get null values into a ComboBox is with the null object pattern. (And thankfully for me doesn’t require any knowledge of WPF control internals to implement).

Here’s what my null object looked like:

public class NullCurve : IFxCurve, IEquatable<NullCurve>
{
    public string Name { get { return ""; } }

    public void DoStuff() {} // Has no implementation

    // Note the equality overload. Null objects are value types -- they
    // have no identity, and are all equal.
    public bool Equals(NullCurve other)
    {
        return other != null;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as NullCurve);
    }

    public override int GetHashCode() { return -1; }
}

To use it, you simply pop a null object at the start of your list. And check whether it was selected on submit:

public class FxCurveSelectionViewModel : ViewModelBase
{
    public ObserableCollection<IFxCurve> AvailableCurves { get; private set; }
    public IFxCurve SelectedCurve { get; set; }

    public FxCurveSelectionViewModel(ICurveRepository curves)
    {
        AvailableCurves = new ObservableCollection<IFxCurve>();
        AvailableCurves.Add(new NullCurve());
        AvailableCurves.AddRange(curves.GetAllCurves());
    }

    public void Submit()
    {
        if (SelectedCurve.Equals(new NullCurve()))
            // nothing was selected
    }
}

XAML binding is standard; no need to change anything because we handle it all in the view model. Which arguably is not the most DRY solution long-term, but sufficient until I learn more about WPF internals to do it elegantly with XAML.

March 27th, 2010 | 6 Comments

At work, I am currently working on a small WPF app that we want to keep as a simple standalone exe. However, it has dependencies on several third-party assemblies: SharpZipLib, Unity, ServiceLocator, etc.

Microsoft has handy tool called ILMerge that merges multiple .NET assemblies into a single dll or exe. Unfortunately, it doesn’t support WPF applications, because of the way XAML is compiled.

Instead, you can use another approach — include all your referenced third-party assemblies as embedded resources of the exe:

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
        AppDomain.CurrentDomain.AssemblyResolve +=
            new ResolveEventHandler(ResolveAssembly);

        // proceed starting app...
    }

    static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
    {
        Assembly parentAssembly = Assembly.GetExecutingAssembly();

        var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
        var resourceName = parentAssembly.GetManifestResourceNames()
            .First(s => s.EndsWith(name));

        using (Stream stream = parentAssembly.GetManifestResourceStream(resourceName))
        {
            byte[] block = new byte[stream.Length];
            stream.Read(block, 0, block.Length);
            return Assembly.Load(block);
        }
    }
}

Whenever .NET can’t find a referenced assembly, it will call our code and we can provide an Assembly instance ourselves. Note this code expects a sane DLL-naming convention :)

May 14th, 2009 | 7 Comments

Today I am working on my first WPF app, using the WPF Model-View-ViewModel (MVVM) Toolkit. Naturally, we are using TDD — like ASP.NET MVC, WPF ViewModels and ICommands lend themselves very nicely to unit testing, even around difficult dependencies like OpenFileDialog.

Anyway, one problem I am seeing repeated is writing tests for PropertyChanged events firing at the correct time. This is required so that WPF views can display updated values when something changes. For a test helper, I wrote a quick disposable event listener and extension method for this:

[TestMethod]
public void Should_raise_pack_path_property_changed_event()
{
    viewModel.AssertRaisesPropertyChangedFor("PackPath");

    viewModel.OnFileSelected(@"C:\foo.zip");
}

An assertion will fail if the PropertyChanged event does not fire with the correct property name. Here is the extension method:

public static class INotifyPropertyChangedExtensions
{
    public static void AssertRaisesPropertyChangedFor(this INotifyPropertyChanged obj,
        string propertyName)
    {
        new PropertyChangedEventListener(obj, propertyName);
    }
}

… and the event listener:

/// <summary>
/// Helper class for asserting a PropertyChanged event gets raised for a particular
/// property. If it hasn't been called by the time this object is disposed, an
/// assertion will fail.</summary>
public class PropertyChangedEventListener : IDisposable
{
    bool wasRaised = false;
    readonly string expectedPropertyName;
    bool IsDisposed = false;
    readonly INotifyPropertyChanged obj;

    public PropertyChangedEventListener(INotifyPropertyChanged obj, string propertyName)
    {
        if (obj == null)
            throw new ArgumentNullException("obj");

        if (propertyName == null)
            throw new ArgumentNullException("propertyName");

        this.obj = obj;
        this.expectedPropertyName = propertyName;
        obj.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
    }

    void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (this.expectedPropertyName.Equals(e.PropertyName))
            this.wasRaised = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool Disposing)
    {
        if (!IsDisposed)
        {
            if (Disposing)
            {
                // Cleanup references...
                this.obj.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged);

                // Assert we got called
                Assert.IsTrue(this.wasRaised,
                    String.Format("PropertyChanged was not raised for property '{0}'",
                        this.expectedPropertyName));
            }
        }

        IsDisposed = true;
    }

    ~PropertyChangedEventListener()
    {
        Dispose(false);
    }
}

It’s not fancy, and it’s probably not thread-safe, but it does the trick for our app.

May 11th, 2009 | 7 Comments