Learn Prism’s Event Aggregator

14 minute read

Learn the section Event Aggregator from RRISM LIBRARY Documentation.

It’s a translation of that, but as a memo.
If you don’t speak Japanese, go back to English and understand it. .. ..

The Prism Library provides an event mechanism that enables communications between loosely coupled components in the application. This mechanism, based on the event aggregator service, allows publishers and subscribers to communicate through events and still do not have a direct reference to each other.

The EventAggregator provides multicast publish/subscribe functionality. This means there can be multiple publishers that raise the same event and there can be multiple subscribers listening to the same event. Consider using the EventAggregator to publish an event across modules and when sending a message between business logic code, such as controllers and presenters.

Events created with the Prism Library are typed events. This means you can take advantage of compile-time type checking to detect errors before you run the application. In the Prism Library, the EventAggregator allows subscribers or publishers to locate a specific EventBase. The event aggregator also allows for multiple publishers and multiple subscribers, as shown in the following illustration.
(Google Translate)
The Prism Library provides an event mechanism that allows communication between loosely coupled components within your application. This mechanism, which is based on the event aggregator service, allows publishers and subscribers to communicate through events, but not directly to each other.

EventAggregator provides multicast publish / subscribe functionality. That is, there can be multiple publishers that raise the same event, and multiple subscribers that listen for the same event. Consider using EventAggregator to publish events between modules and sending messages between business logic code such as controllers and presenters.

Events created in the Prism Library are typed events. This means that you can take advantage of compile-time type checking to detect errors before running your application. The Prism Library allows subscribers or publishers to find a particular EventBase through EventAggregator. The event aggregator can also be used by multiple publishers and subscribers, as shown in the following figure.
image.png

image.png

IEventAggregator
The EventAggregator class is offered as a service in the container and can be retrieved through the IEventAggregatorinterface. The event aggregator is responsible for locating or building events and for keeping a collection of the events in the system.
(Google Translate)
The EventAggregator class is provided as a service inside the container and can be retrieved through the IEventAggregator interface. The event aggregator is responsible for finding or building events and maintaining a collection of events in your system.

public interface IEventAggregator
{
    TEventType GetEvent<TEventType>() where TEventType : EventBase;
}

The EventAggregator constructs 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.
(Google Translate)
EventAggregator builds the event on the first access, if it hasn’t been built yet. This eliminates the need for publishers or subscribers to determine if an event is available.
PubSubEvent
The real work of connecting publishers and subscribers is done by the PubSubEvent class. This is the only implementation of the EventBase class that is included in the Prism Library. This class maintains the list of subscribers and handles event dispatching to the subscribers.

The PubSubEvent 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 PubSubEvent class.
(Google Translate)
The actual work of connecting publishers and subscribers is done by the PubSubEvent class. This is the only implementation of the EventBase class included in the Prism Library. This class maintains a list of subscribers and handles event dispatches to subscribers.

The PubSubEvent class is a generic class that requires the payload type to be defined as a generic type. This allows publishers and subscribers to run at compile time to provide the appropriate methods for successful event connections. The following code shows a partial definition of the PubSubEvent class.

NOTE
PubSubEvent can be found in the Prism.Events namespace which is located in the Prism.Core NuGet package.
(Google Translate)
Caution
PubSubEvent is located in the Prism.Events namespace in the Prism.Core NuGet package.
Creating an Event
The PubSubEvent is intended to be the base class for an application's or module's specific events. TPayLoad is the type of the event's payload. The payload is the argument that will be passed to subscribers when the event is published.

For example, the following code shows the TickerSymbolSelectedEvent. The payload is a string containing the company symbol. Notice how the implementation for this class is empty.
(Google Translate)
PubSubEvent is intended to be the base class for a particular event in your application or module. TPayLoad is the type of event payload. The payload is the argument passed to the subscriber when the event is fired.

For example, the following code shows a TickerSymbolSelectedEvent. The payload is a string containing company symbols. Note that the implementation of this class is empty.

public class TickerSymbolSelectedEvent : PubSubEvent<string>{}

NOTE
In a composite application, the events are frequently shared between multiple modules, so they are defined in a common place. It is common practice to define these events in a shared assembly such as a “Core” or “Infrastructure” project.
(Google Translate)
Caution
In composite applications, events are often shared between modules and are therefore defined in a common place. It is common practice to define these events in shared assemblies such as “core” and “infrastructure” projects.
Publishing an Event
Publishers raise an event by retrieving the event from the EventAggregator and calling the Publish method. To access the EventAggregator, you can use dependency injection by adding a parameter of type IEventAggregator to the class constructor.
(Google Translate)
The publisher raises the event by getting the event from the EventAggregator and calling the Publish method. To access EventAggregator, you can use dependency injection by adding a parameter of type IEventAggregator to the class constructor.

public class MainPageViewModel
{
    IEventAggregator _eventAggregator;
    public MainPageViewModel(IEventAggregator ea)
    {
        _eventAggregator = ea;
    }
}

The following code demonstrates publishing the TickerSymbolSelectedEvent.
(Google Translate)
The following code shows the publication of the TickerSymbolSelectedEvent.

_eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("STOCK0");

Subscribing to Events
Subscribers can enlist with an event using one of the Subscribe method overloads available on the PubSubEvent class.
(Google Translate)
Subscribers can join the event using one of the Subscribe method overloads available in the PubSubEvent class.

public class MainPageViewModel
{
    public MainPageViewModel(IEventAggregator ea)
    {
        ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews);
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}

There are several ways to subscribe to PubSubEvents. Use the following criteria to help determine which option best suits your needs:

・ If you need to be able to update UI elements when an event is received, subscribe to receive the event on the UI thread.
・ If you need to filter an event, provide a filter delegate when subscribing.
・ If you have performance concerns with events, consider using strongly referenced delegates when subscribing and then manually unsubscribe from the PubSubEvent.
・ If none of the preceding is applicable, use a default subscription.

The following sections describe these options.
(Google Translate)
There are several ways to subscribe to PubSubEvents. Use the following criteria to determine the option that best suits your needs.

· If you need to be able to update UI elements when an event is received, subscribe to the UI thread to receive the event.
· If you need to filter events, provide a filter delegate when subscribing.
· If you have performance issues with the event, consider using a delegate that is strongly referenced when subscribing, and then manually unsubscribe from PubSubEvent.
・ If the above does not apply, please use the default subscription.

The next section describes these options.
Subscribing on the UI Thread
Frequently, subscribers will need to update UI elements in response to events. In WPF, only a UI thread can update UI elements.

By default, the subscriber receives the event on the publisher’s thread. If the publisher sends the event from the UI thread, the subscriber can update the UI. However, if the publisher’s thread is a background thread, the subscriber may be unable to directly update UI elements. In this case, the subscriber would need to schedule the updates on the UI thread using the Dispatcher class.

The PubSubEvent provided with the Prism Library can assist by allowing the subscriber to automatically receive the event on the UI thread. The subscriber indicates this during subscription, as shown in the following code example.
(Google Translate)
Subscribers often need to update UI elements in response to events. In WPF, only UI threads can update UI elements.

By default, subscribers receive events in the publisher’s thread. If the publisher sends an event from the UI thread, the subscriber can update the UI. However, if the publisher thread is a background thread, subscribers may not be able to update UI elements directly. In this case, the subscriber must use the Dispatcher class to schedule updates in the UI thread.

The PubSubEvent provided by the Prism Library can be assisted by allowing subscribers to automatically receive events in the UI thread. The subscriber indicates this during the subscription, as shown in the following code example.

public class MainPageViewModel
{
    public MainPageViewModel(IEventAggregator ea)
    {
        ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews, ThreadOption.UIThread);
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}

The following options are available for ThreadOption:

-PublisherThread: Use this setting to receive the event on the publishers’ thread. This is the default setting.
-BackgroundThread: Use this setting to asynchronously receive the event on a .NET Framework thread-pool thread.
-UIThread: Use this setting to receive the event on the UI thread.
(Google Translate)
ThreadOption has the following options:

· PublisherThread: Use this setting to receive events in the publisher’s thread. This is the default setting.
· BackgroundThread: Use this setting to receive events asynchronously on .NET Framework thread pool threads.
• UIThread: Use this setting to receive events on the UI thread.

NOTE
In order for PubSubEvent to publish to subscribers on the UI thread, the EventAggregator must initially be constructed on the UI thread.
(Google Translate)
Caution
To publish PubSubEvent to UI thread subscribers, you must first build the EventAggregator in the UI thread.

Subscription Filtering
Subscribers may not need to handle every instance of a published event. In these cases, the subscriber can use the filter parameter. The filter parameter is of type System.Predicate and is a delegate that gets executed when the event is published to determine if the payload of the published event matches a set of criteria required to have the subscriber callback invoked. If the payload does not meet the specified criteria, the subscriber callback is not executed.

Frequently, this filter is supplied as a lambda expression, as shown in the following code example.
(Google Translate)
Subscribers may not need to handle every instance of an event that has been published. In such cases, subscribers can use filter parameters. The filter parameter is of type System.Predicate , which is executed when the event is fired and determines if the payload of the fired event matches the set of criteria needed to call the subscriber callback. It is a delegate. If the payload does not meet the specified criteria, no subscriber callback will be executed.

This filter is often provided as a lambda expression, as shown in the following code example.

public class MainPageViewModel
{
    public MainPageViewModel(IEventAggregator ea)
    {
        TickerSymbolSelectedEvent tickerEvent = ea.GetEvent<TickerSymbolSelectedEvent>();
        tickerEvent.Subscribe(ShowNews, ThreadOption.UIThread, false, 
                              companySymbol => companySymbol == "STOCK0");
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}

NOTE
The Subscribe method returns a subscription token of type Prism.Events.SubscriptionToken that can be used to remove a subscription to the event later. This token is particularly useful when you are using anonymous delegates or lambda expressions as the callback delegate or when you are subscribing the same event handler with different filters.
(Google Translate)
Caution
The Subscribe method returns a subscription token of type Prism.Events.SubscriptionToken. You can use this to later remove the subscription to the event. This token is especially useful when using anonymous delegates or lambda expressions as callback delegates, or when subscribing to the same event handler with different filters.

NOTE
It is not recommended to modify the payload object from within a callback delegate because several threads could be accessing the payload object simultaneously. You could have the payload be immutable to avoid concurrency errors.
(Google Translate)
Caution
We do not recommend modifying the payload object from within the callback delegate, as multiple threads may be accessing the payload object at the same time. The payload can be immutable to avoid concurrency errors.
Subscribing Using Strong References
If you are raising multiple events in a short period of time and have noticed performance concerns with them, you may need to subscribe with strong delegate references. If you do that, you will then need to manually unsubscribe from the event when disposing the subscriber.

By default, PubSubEvent maintains a weak delegate reference to the subscriber’s handler and filter on subscription. This means the reference that PubSubEvent holds on to will not prevent garbage collection of the subscriber. Using a weak delegate reference relieves the subscriber from the need to unsubscribe and allows for proper garbage collection.

However, maintaining this weak delegate reference is slower than a corresponding strong 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 references with PubSubEvent. If you do use strong delegate references, your subscriber should unsubscribe to enable proper garbage collection of your subscribing object when it is no longer used.

To subscribe with a strong reference, use the keepSubscriberReferenceAlive parameter on the Subscribe method, as shown in the following code example.
(Google Translate)
If you raise multiple events in a short period of time and notice performance issues, you may need to subscribe to a strong delegate reference. In that case, you will need to manually unsubscribe from the event when you drop the subscriber.

By default, PubSubEvent maintains a weak delegate reference to the subscriber’s handler and filters subscriptions. In other words, the references held by PubSubEvent do not interfere with the subscriber’s garbage collection. Weak delegate references eliminate the need for subscribers to unsubscribe and allow for proper garbage collection.

However, maintaining this weak delegate reference is slower than the corresponding strong reference. For most applications, this performance is not noticeable, but if your application publishes a large number of events in a short period of time, you may need to use strong references in PubSubEvent. If you use strong delegate references, the subscriber must unsubscribe and enable proper garbage collection when the subscribed object is no longer in use.

To subscribe with a strong reference, use the keepSubscriberReferenceAlive parameter in the Subscribe method, as shown in the following code example.

public class MainPageViewModel
{
    public MainPageViewModel(IEventAggregator ea)
    {
        bool keepSubscriberReferenceAlive = true;
        TickerSymbolSelectedEvent tickerEvent = ea.GetEvent<TickerSymbolSelectedEvent>();
        tickerEvent.Subscribe(ShowNews, ThreadOption.UIThread, keepSubscriberReferenceAlive, 
                              companySymbol => companySymbol == "STOCK0");
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}

The keepSubscriberReferenceAlive parameter is of type bool:

・ When set to true, the event instance keeps a strong reference to the subscriber instance, thereby not allowing it to get garbage collected. For information about how to unsubscribe, see the section Unsubscribing from an Event later in this topic.
When set to false (the default value when this parameter omitted), the event maintains a weak reference to the subscriber instance, thereby allowing the garbage collector to dispose the subscriber instance when there are no other references to it. When the subscriber instance gets collected, the event is automatically unsubscribed.
(Google Translate)
The type of the keepSubscriberReferenceAlive parameter is bool.

· If set to true, the event instance will maintain a strong reference to the subscriber instance and will not be able to perform garbage collection. See the Unsubscribing from Events section later in this topic for information on how to unsubscribe.
· When set to false (the default value if this parameter is omitted), the event maintains a weak reference to the subscriber instance so that the garbage collector can destroy the subscriber instance if there are no other references. Events are automatically unsubscribed when subscriber instances are collected.

Unsubscribing from an Event
If your subscriber no longer wants to receive events, you can unsubscribe by using your subscriber’s handler or you can unsubscribe by using a subscription token.

The following code example shows how to directly unsubscribe to the handler.
(Google Translate)
When the subscriber no longer needs to receive the event, you can use the subscriber’s handler to unsubscribe or use the subscription token to unsubscribe.

The following code example shows how to unsubscribe directly to a handler.

public class MainPageViewModel
{
    TickerSymbolSelectedEvent _event;
    public MainPageViewModel(IEventAggregator ea)
    {
        _event = ea.GetEvent<TickerSymbolSelectedEvent>();
        _event.Subscribe(ShowNews);
    }

    void Unsubscribe()
    {
        _event.Unsubscribe(ShowNews);
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}

The following code example shows how to unsubscribe with a subscription token. The token is supplied as a return value from the Subscribe method.
(Google Translate)
The following code example shows how to unsubscribe using a subscription token. The token is provided as the return value from the Subscribe method.

public class MainPageViewModel
{
    TickerSymbolSelectedEvent _event;
    SubscriptionToken _token;
    public MainPageViewModel(IEventAggregator ea)
    {
        _event = ea.GetEvent<TickerSymbolSelectedEvent>();
        _token = _event.Subscribe(ShowNews);
    }

    void Unsubscribe()
    {
        _event.Unsubscribe(_token);
    }

    void ShowNews(string companySymbol)
    {
        //implement logic
    }
}