It’s hard to talk about WPF UI architecture without talking about MVVM, so lets start there, shall we? The MVVM pattern (or presentation model) deals with a number of things, but concurrency isn’t one of them (and perhaps nor should it). When applying the Presentation Model to WPF there is a certain amount of discomfort to be felt, particularly when dealing with modifying collections from non-UI threads, but for the most part we’re left to our own devices using the WPF dispatcher, and the usual suspects of synchronization primitives like threads, locks and mutexes. Although Microsoft has been improving the experience for developers with recent releases like the Task Parallel Library and Reactive Extensions, and this has been built on with libraries like Reactive UI none of these (to my mind at least) attacks the problem of shared state.
The Fractal Application Architecture
With this in mind I started looking at a way of structuring the UI for WPF applications that is in many ways akin to the way many distributed ‘enterprise’ applications are architected – using and actor model a message publishing and subscription model (AKA PUB/SUB) or message bus.
The Simplest thing that could Possibly Work
What I’ve come up with so far is pretty under-whelming but I’m hoping to build on this to create something that is actually useful. My current sample application doesn’t use MVVM, data binding or anything like that, but merely looks at setting up some message passing infrastructure using 0MQ, allowing two threads running in the same process to send messages to each-other, where one of those threads is driving a WPF UI.
You can view all the pertinent source code in a single file here or get the latest source as part of my learnwpf.com samples project on bitbucket.
In the fullness of time I’d like to build up an example that deals with
- passing data types more complex than just strings
- integration with MVVM and other traditional WPF patterns and idioms.
- handles different messaging styles including pub/sub, push/pull etc.
- reliability improvements so that exceptions in a single service/actor don’t bring down the whole process.
- experiment with moving some actors out-of-process (Location Transparency)
You can insert your favourite quote about most complicated concurrent programs having half a poor erlang implementation in them somewhere here.