Cet article est disponible en francais.

Recently, I wrote an article about WinForms, DataBinding and Updates from multiple threads, where I showed how to externalize the execution of event handler code on the UI thread.

I used a technique based on Action<Action> that takes advantage of closures, and the fact that an action will carry its context down to the point where it is executed. All this with no strings attached.

This concept of externalization can be revisited with the Reactive Extensions, and the IScheduler interface.

 

The Original Sample

But let's get right to the original code sample :

[code:c#]

    public MyController(Action<Action> synchronousInvoker)
    {
        _synchronousInvoker = synchronousInvoker;
        ...
    }

[/code]

This code is the constructor of the controller for my form, and the synchronous invoker action will take something like this :

[code:c#]

    _controller = new MyController(a => Invoke(a));
[/code]

And the invoker lambda is used like this :

[code:c#]
    _synchronousInvoker(
        () => PropertyChanged(this, new PropertyChangedEventArgs("Status"))
    );

[/code]

Where Invoke is actually Control.Invoke(), used to execute code on the UI Thread where updates to the UI controls can be safely executed.

While the Action<Action> trick is working just fine in acheiving the isolation of concerns, it is not very obvious just by looking at the constructor signature what you are supposed to pass to it.

 

Using the IScheduler interface

To be able to abstract the location used to execute the content of Reactive operators, the Rx team introduced the concept of Scheduler, with a bunch of default scheduler implementations.

It basically exposes an abstracted way for users of the IScheduler instance to schedule the execution of a method in the specific way defined by the scheduler. In our case, we want to execute our handler code on the WinForms message pump, and "there's a scheduler for that".

The sample can be easily updated to use the IScheduler instead of the Action<Action> delegate, and make use of the IScheduler.Schedule() method.

[code:c#]

    public MyController(ISheduler scheduler)
    {
        _scheduler = scheduler;
        ...
    }

[/code]

And replace the call by :

[code:c#]
    _scheduler.Schedule(
        () => PropertyChanged(this, new PropertyChangedEventArgs("Status"))
    );

[/code]

Not a very complex modification, but it is far more readable.

And we can use the provided scheduler for the Winforms, the yet undocumented System.Concurrency.ControlScheduler which is not in the Scheduler class because it cannot be created statically and requires a Control instance :

[code:c#]

    _controller = new MyController(new ControlScheduler(this));
[/code]

where this is an instance of a control.

This is much better, and for the unit testing of the Controller, you can easily use the System.Concurrency.CurrentThreadScheduler, because you don't need to switch threads in this context.

 

What about the Reactive Extensions and Silverlight for Windows Phone 7 ?

In a very strange move, the WP7 team moved the IScheduler class from System.Concurrency to the very specific Microsoft.Phone.Reactive namespace.

I do not quite understand the change of namespace, and it makes code that used to compile easily on both platforms not compatible.

Maybe they considered the Reactive Extensions implementation for Windows Phone too different from the desktop implementation... But the compact framework was built around that assertion, and most of the common code stays in the same namespaces.

If someone has an explanation for that strange refactoring, I'm listening :)