Event Aggregator
Retired Content |
---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
The EventAggregator service is primarily a container for events that allow decoupling of publishers and subscribers so they can evolve independently. This decoupling is useful in modularized applications because new modules can be added that respond to events defined by the shell or, more likely, other modules.
In the Composite Application Library, EventAggregator allows subscribers or publishers to locate a specific EventBase. The event aggregator also allows for multiple publishers and multiple subscribers, as shown in Figure 1.
Figure 1
Event Aggregator
IEventAggregator
The **EventAggregator **class is offered as a service in the container and can be retrieved through the IEventAggregator interface. The event aggregator is responsible for locating or building events and for keeping a collection of the events in the system.
public interface IEventAggregator
{
TEventType GetEvent<TEventType>() where TEventType : EventBase;
}
The EventAggregator will construct the event on its first access if it has not already been constructed. This relieves the publisher or subscriber from needing to determine whether the event is available.
CompositeWpfEvent
The real work of connecting publishers and subscribers is done by the CompositeWpfEvent class. This is the only implementation of the EventBase class that comes out of the box in the Composite Application Library. This class maintains the list of subscribers and handles event dispatching to the subscribers.
The CompositeWpfEvent class is a generic class that requires the payload type to be defined as the generic type. This helps enforce, at compile time, that publishers and subscribers provide the correct methods for successful event connection. The following code shows a partial definition of the CompositeWpfEvent class.
public class CompositeWpfEvent<TPayload> : EventBase
{
…
public SubscriptionToken Subscribe(Action<TPayload> action);
public SubscriptionToken Subscribe(Action<TPayload> action,
ThreadOption threadOption);
public virtual SubscriptionToken Subscribe(Action<TPayload> action,
ThreadOption threadOption, bool keepSubscriberReferenceAlive,
Predicate<TPayload> filter);
public virtual void Publish(TPayload payload);
public virtual void Unsubscribe(Action<TPayload> subscriber);
public virtual void Unsubscribe(SubscriptionToken token);
…
}
The CompositeWpfEvent is intended to be the base class for an application's or module's specific events. For example, the following code shows the TickerSymbolSelectedEvent in the Stock Trader Reference Implementation (Stock Trader RI).
public class TickerSymbolSelectedEvent : CompositeWpfEvent<string>{}
Note
In a composite application, the events are frequently shared between multiple modules so are defined in a common place. In the Stock Trader RI, this is done in the StockTraderRI.Infrastructure project.
Subscribing to an Event
Subscribers can enlist with an event using one of the CompositeWpfEvent available Subscribe method overloads. There are a number of options for subscribing to CompositeWpfEvents. Use the following criteria to help determine which option best suits your needs:
- If you need to be able to update user-interface elements when an event is received, subscribe to receive the event on the user interface thread.
- If you need to filter an event, provide a filter delegate when subscribing.
- If you have noticed performance concerns with your events, consider using strongly-referenced delegates when subscribing and manually unsubscribe from the CompositeWpfEvent.
- If none of the preceding is applicable, use a default subscription.
Default Subscriptions
For a minimal or default subscription, the subscriber must provide a callback method with the appropriate signature that receives the event notification. For example, the handler for the TickerSymbolSelectedEvent requires the method take a string parameter, as shown here.
public void Initialize()
{
eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews);
}
public void ShowNews(string companySymbol)
{
articlePresentationModel.SetTickerSymbol(companySymbol);
}
Subscribing on the User Interface Thread
Frequently, subscribers will need to update user interface elements in response to events. In Windows Presentation Foundation (WPF), only a UI thread can update user interface elements. By default, the subscriber receives the event on the publisher's thread so if the publisher sends the event from the UI thread, the subscriber will be able to update the user interface.
However, if the publisher's thread is a background thread, the subscriber may be unable to directly update user interface elements. Instead, it would need to schedule the updates on the UI thread using the Windows Presentation Foundation's Dispatcher class. The CompositeWpfEvent provided with the Composite Application Library can assist by allowing the subscriber to automatically receive the event on the UI thread. The subscriber must indicate this during subscription, as shown in the following code.
public void Initialize()
{
eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews,
ThreadOption.UIThread);
);
}
public void ShowNews(string companySymbol)
{
articlePresentationModel.SetTickerSymbol(companySymbol);
}
The following options are available for ThreadOption:
- Publisher. Use this setting to receive the event on the publishers' thread. This is the default setting.
- Background. Use this setting to receive the event on a .NET Framework thread-pool thread.
- UIThread. Use this setting to receive the event on the user interface thread.
Subscription Filtering
Subscribers may not need to handle every instance of a published event. In these cases, the subscriber can subscribe and supply a delegate that filters the event before the registered handler is called. Frequently, this filter is supplied as a lambda expression, as shown in the following code.
FundAddedEvent fundAddedEvent = eventAggregator.GetEvent<FundAddedEvent>();
fundAddedEvent.Subscribe(FundAddedEventHandler,
ThreadOption.UIThread, false,
fundOrder => fundOrder.CustomerId == _customerId);
Subscribing Using Strong References
If you have noticed performance concerns with your events, you may need to subscribe with strong delegate references—and therefore manually unsubscribe from the event—instead of the default weak delegate references maintained by CompositeWpfEvent.
By default,** CompositeWpfEvent** maintains a weak delegate reference to the subscriber's handler and filter on subscription. This means the reference that CompositeWpfEvent holds to the subscriber will not prevent garbage collection of the subscriber. Using a weak delegate reference relieves the subscriber from the need to unsubscribe to enable proper garbage collection. However, maintaining this weak delegate reference is slower than a corresponding strong delegate reference. For most applications, this performance will not be noticeable, but if your application publishes a large number of events in a short period of time, you may need to use strong delegate references with CompositeWpfEvent to achieve reasonable performance. If you do use strong delegate references, your subscriber should unsubscribe to enable proper garbage collection of your subscribing object.
To subscribe with a strong reference, use the keepSubscriberReferenceAlive option on the Subscribe method, as shown in the following code.
FundAddedEvent fundAddedEvent = eventAggregator.GetEvent<FundAddedEvent>();
bool keepSubscriberReferenceAlive = true;
fundAddedEvent.Subscribe(FundAddedEventHandler,
ThreadOption.UIThread, keepSubscriberReferenceAlive,
fundOrder => fundOrder.CustomerId == _customerId);
Publishing an Event
Publishers raise an event by retrieving the event from the EventAggregator and calling the Publish method. For example, the following code demonstrates publishing the TickerSymbolSelectedEvent.
EventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish(e.Value);
Unsubscribing from an Event
If your subscriber no longer wants to receive events, you can unsubscribe using your subscriber's handler directly or you can unsubscribe by using a subscription token. The following example shows how to directly unsubscribe to the handler.
compositeWpfEvent.Subscribe(
FundAddedEventHandler,
ThreadOption.PublisherThread);
compositeWpfEvent.Unsubscribe(FundAddedEventHandler);
To unsubscribe with a subscription token, the token supplied during the subscribe process can be supplied to the Unsubscribe method call, as shown here.
FundAddedEvent fundAddedEvent = eventAggregator.GetEvent<FundAddedEvent>();
subscriptionToken = fundAddedEvent.Subscribe(FundAddedEventHandler,
ThreadOption.UIThread, false,
fundOrder => fundOrder.CustomerId == _customerId);
fundAddedEvent.Unsubscribe(subscriptionToken);
More Information
For more information about events in the Composite Application Library, see the following resources:
- Event Aggregation QuickStart
- How to: Create and Publish Events
- How to: Subscribe and Unsubscribe to Events
- Event Aggregator on Martin Fowler's Web site
Retired Content |
---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |