A frequent problem when using the MVVM (Model View ViewModel) pattern is how to send messages to an object far away in the object graph.
For example- a view model for the main window opens a detail area (or popup window) backed by a detail view model. The detail view model doesn’t know how it is being presented, but knows it needs to be closed somehow. What the best way to communicate to its parent, and the view presenting its parent, that it needs to close?
This is fairly trivial example, but this comes up a lot. A view model backing a portion of a page may need to cause an update to view models backing other parts of the page. It can get over-complicated trying to route everything up to the parent and back down to the siblings.
Before I’ve solved this problem the complex way- by managing two way relationships between parent and child view models. It’s not good.
This time I found a better pattern. It’s very close to this: http://martinfowler.com/eaaDev/EventAggregator.html, but also resembles a publish/subscribe messaging system.
I wrote a MessageRouter class, with the following signature:
public void Register<TMessage>(object recipient, Action<TMessage> action);
Any object can register to receive messages of type TMessage. The object provides a delegate that simply receives the message object.
Any other object can send the message to all registered recipients by calling send with an instance of the message.
An object can unregister (and clear up the reference to it so it can be garbage collected) by called Unregister and passing itself as an argument.
I put this MessageRouter in global scope- for my Silverlight app, it’s a property on the application instance. It could otherwise be a singleton. But now view models across the application can subscribe to messages from any other view model. (or in some cases view objects participate too).