Posted by Mark Withall: 2013-08-29
In a previous article we looked at the two most important features of an MVVM framework. Here we look at another common feature.
Most, if not all, mainstream MVVM frameworks provide some sort of event aggregator/message bus. This makes communication between viewmodels easier than doing it manually via events or callback injection (both of which require too much knowledge of either the sender or receiver and tend to be the cause of accidental memory leaks).
Fortunately, it is straightforward to create a simple event aggregator. We can define the API using the following set of interfaces.
ISubscriber<TMessage>
public interface ISubscriber<in TMessage>
{
void HandleMessage(TMessage message);
}
This allows a class to implement multiple event handlers without the need to switch on the message type.
ISubscriberStore
public interface ISubscriberStore
{
void Add<TMessage>(ISubscriber<TMessage> subscriber);
IEnumerable<ISubscriber<TMessage>> Subscribers<TMessage>();
}
No Remove
method, as subscriptions will be stored as weak references and are cleaned up on calls to Subscribers.
IMessageAggregator
public interface IMessageAggregator
{
void Subscribe<TMessage>(ISubscriber<TMessage> subscriber);
void Publish<TMessage>(TMessage message);
}
No Unsubscribe
method, as subscriptions are stored as weak references and are cleaned up on calls to publish.
Notice that messages can be anything, though it is probably sensible to wrap them in a well named class.
As an aside, I don’t generally go in for naming interfaces with an ‘I’ prefix. There are many arguments in favour of this on the Interweb. However, for libraries, where one doesn’t know who is using it (or how), I prefer the explicit approach.
Test Plan
SubscriberStore
SubscriberStore
implementsISubscriberStore
- Add adds a subscriber to the underlying dictionary list for the particular message type
Subscribers
returns all subscribers for the given message typeSubscribers
removes all dead subscribers for the given message typeSubscribers
doesn’t return null subscribers
MessageAggregator
MessageAggregator
implementsIMessageAggregator
Subscribe
adds to the underlyingISubscriberStore
Publish
callsHandleMessage
on all subscribers for the given message type
Also, an integration/acceptance test that has multiple publishers and subscribers (implementing multiple types each) is probably warranted.
The actual implementation details of these classes is left as an exercise for the reader but will hopefully be the subject of a later video.
Tweet Follow @MarkWithall