Decoupled Communication with Prism (Event Aggregation)


In my previous post, I discussed commanding and how you can hook up invokers (e.g. buttons and menu items), global CompositeCommands, and module level command instances. If you need the sending of a message to be initiated by a user gesture such as a button click, Commands may be a good choice. If you need the sending of a message to be initiated by business logic code, such as in a controller or presenter, you should consider using the EventAggregator.

In the case where a button has been clicked, validation has passed, and work has been completed, it is often useful to alert the rest of the application that this event has occurred. Let’s say the the "Process Order" button has been pressed. If the order is successfully processed, other modules may want to know so that they can update their views: "Processed Orders List", "Pending Orders List", "Available Inventory"… For this type of communication, we developed EventAggregator.

EventAggregator provides multicast publish/subscribe functionality. There can be multiple publishers that publish/fire/raise the same event and there can be many subscribers who listen to the same event. If you define the event in a common assembly, EventAggregator can be used across module assemblies.

Defining an event:

Defining an EventAggregator event is as simple as extending WpfEvent<TPayload> supplying the payload type.

public class TickerSymbolSelectedEvent : WpfEvent<string> { }

For the TickerSymbolSelectedEvent, publishers will need to provide a string argument, and subscribers can expect to receive a string argument.

EventAggregator Singleton Service:

Make sure that the EventAggregator instance is treated as a singleton. One way to do this is to register this type in your dependency injection container as a single instance and always use the container to resolve the EventAggregator.

unityContainer.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());

The EventAggregator is merely a singleton factory. When you call its GetEvent<TEventType> method, it will return an instance of TEventType that was previously requested, or create a new instance and keep track of it.

Publishing an event:

Use the singleton instance of the EventAggregator to get an instance of the event to which you want to work with. Call the event’s Publish method supplying the message payload. The WpfEvent<TPayload> base class manages all the subscriptions and handles cross thread messaging.

eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("MSFT");

Subscribing to an event:

Again, use the singleton instance of EventAggregator to get an instance of the event to which you want to work with. Call the event’s Subscribe method supplying a delegate to handle the receiving of the message. You can optionally provide a ThreadOption to specify which thread on which you would like to receive the message (publisher’s thread, UI thread, or background thread). You can optionally provide a boolean to specify whether or not to provide a strong reference to the subscriber. This defaults to false so that the subscriber can be garbage collected even though it did not unregister to our EventAggregator event. Finally you can optionally provide a predicate delegate to filter the messages based on your custom criteria. Please note that you can only filter on properties of the message payload.

eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews, ThreadOption.UIThread);

Comments (5)

  1. Francis has been a busy man lately on his blog with a series of posts on the various loosely coupled

  2. Glenn Block says:

    Francis has been a busy man lately on his blog with a series of posts on the various loosely coupled

  3. Francis has been a busy man lately on his blog with a series of posts on the various loosely coupled

  4. Anthony says:

    What if you modify, change, add events to the publisher, then how do you enforce various OEM subscribers (say other companies that are using your framework) that these changes occured? If you use an interface then the changes are obvious, if you use the event aggregator then it seems the changes could break code and lead to confusion for hot fixes, patches, and upgrades to an existing framework.

  5. Blackie says:

    Any advice on unit testing events subscribed on ThreadOption.UIThread ??

    It looks for Application.Current.Dispatcher which does not exist in a unit test, would be ideal there was a way to direct it to use another thread just for testing as the only reason I’ve so far used the UIThread is to make changes to a view model and have the view update via data binding which i’m not attempting to unit test – just that the model changes.

    thanks