Intersoft ClientUI Documentation
Event Aggregator Overview
Event aggregator is an advanced event manager that facilitates the decoupling of publisher and subscribers messaging between different part of applications. It channels events from multiple objects into a single object to simplify registration for clients. Event aggregator is an ideal pattern for applications built with MVVM pattern due to its loosely-coupling messaging capability.

This topic describes the concept of event aggregator in ClientUI, and explains how to register and publish events using event aggregator.

Event Aggregator Concept

In general, Silverlight and WPF application development support two kind of event handling, the .NET native event handler and Routed Events. While these event handling strategies fit in most applications, there are certain scenarios where they may not be ideal.

One of the scenarios is the event handling strategies in MVVM applications particularly when communication is required across multiple ViewModels. The classic event handling strategies cannot support this scenario because they require a strong reference to the target objects, while the best practice in MVVM applications require the ViewModel to be designed in loosely-coupling fashion. This means that a ViewModel may not know the existence of other ViewModels, thus communicating between ViewModels become a natural challenge in an MVVM application.

Event aggregator is designed to provide an elegant solution to this challenge, enabling cross ViewModel communication in loosely-coupled fashion. Event aggregator is built upon the observer pattern and acts as the event hub between the subscribers and publishers. At its simplest form, event aggregator channels events from multiple publishers to multiple registered subscribers such as illustrated in the following diagram.

Event Aggregator in ClientUI

ClientUI includes a built-in event aggregator service that works consistently in both Silverlight and WPF using an identical API. ClientUI’s event aggregator is implemented accordingly to match Martin Fowler’s description and the concept of event aggregator.

ClientUI’s event aggregator is designed to be simple and easy-to-use, yet powerful enough to cover a number of advanced scenarios. It takes only a single line of code to subscribe to an event, as well as for the event publication. See the following examples.

C#
Copy Code
// Subscribe to an event
EventAggregator.Default.Subscribe<MailNotificationEvent, Mail>(OnMailReceived);

// Publish an event
EventAggregator.Default.Publish<MailNotificationEvent, Mail>(this.MailEntity);

As shown in the above example, the event aggregator in ClientUI provides a default static instance allowing developers to subscribe or publish an event in code-efficient manner. Both the Subscribe and Publish methods comprised of two generic parameters for the method signature which are TEventType and TPayLoad. The TEventType represents the type of the event to subscribe or publish, while the TPayLoad represents the type of the message to pass to the event.

In summary, at the heart of ClientUI’s event aggregator is the six methods listed below. It basically involves three aspects, subscribing to an event, publishing an event, and unsubscribe from a previous subscription.

Event Aggregator Methods
Copy Code
public TEventType GetEvent<TEventType>()
                   where TEventType : DelegateEventBase, new();

public void Publish<TEventType, TPayload>(TPayload payload)
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action)
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action, SubscribeOptions options)
                   where TEventType : DelegateEventBase, new();

public SubscriptionToken Subscribe<TEventType, TPayload>(Action<TPayload> action, SubscribeOptions options,
                   Predicate<TPayload> filter) where TEventType : DelegateEventBase, new();

public void Unsubscribe<TEventType, TPayload>(Action<TPayload> action)
                   where TEventType : DelegateEventBase, new();

Using Event Aggregator

To use event aggregator in your application, you will need to perform three major steps:

To better understand how event aggregator works, consider a scenario where a ViewModel is required to communicate to another ViewModel such as in new message notification scenario. When a new message arrives, a notification window should be displayed. In this case, the appearance of notification window is triggerred from the delegate in the event subscription such as shown in the following illustration.

The following sections explain the steps required to implement the sample scenario above.

Defining the MailNotification Event

At the core of the event aggregator service is the DelegateEvent class which implements the members required to work with an event aggregator. ClientUI includes DelegateEvent<TPayload> class allowing you to quickly define an event with certain pay load type.

It is a good practice to always define a named event in your application to improve the readability and maintainability of your code. For the sample scenario above, you will need to define a new event class that represents the MailNotification event such as shown in the following code.

C#
Copy Code
public class MailNotificationEvent : DelegateEvent<Mail>   
{
}

Subscribing to the MailNotification Event

Once the event is defined, you can now subscribe the event in the ViewModel. It is common to perform the subscription in the constructor of the ViewModel class, such as shown below.

C#
Copy Code
public class NotificationViewModel : ViewModelBase, IDisposable
{
     public NotificationViewModel()
     {
          EventAggregator.Default.Subscribe<MailNotificationEvent, Mail>(OnMailReceived);
     }

     /* Event handlers for EA must be public */
     public void OnMailReceived(Mail mail)
     {
          IsNotificationShown = true;
          MailNotification = mail;
     }

     ...
}

As seen in the code above, the class instance subscribes to the MailNotificationEvent which payload type is Mail. When the event is raised, the OnMailReceived function will be invoked. Notice that the parameter type in the delegate method should be exactly the same with the type declared in the TPayLoad in the second generic parameter.

Note that the method delegate declaration used in the event aggregator should have public visibility.

Publishing the MailNotification Event

Event aggregator involves two parties to work properly, subscribers and publishers. Subscriber is a party that listens on the interested events, while publisher sends a signal to the aggregator indicating that a certain event is happening. When published, the event aggregator channels the event to all registered subscribers.

The following code shows how to publish the MailNotification event.

C#
Copy Code
public class MailViewModel : ViewModelBase
{
    private Mail _mailEntity;

    public Mail MailEntity
    {
        get { return _mailEntity; }
        set
        {
            if (_mailEntity != value)
            {
                _mailEntity = value;
                OnPropertyChanged("MailEntity");
            }
        }
    }

    private void OnSubmit(object parameter)
    {
        EventAggregator.Default.Publish<MailNotificationEvent, Mail>(this.MailEntity);
    }

    ... 
}

Enabling Event Filtering

With event aggregator, all registered subscribers will be notified when an event is published through the Publish method. Often times, you might want to listen only in events with certain conditions. ClientUI's event aggregator provides a built-in event filtering feature to address this requirement.

To enable event filtering, you use the Subscribe method that takes the filter parameter and define a method delegate to be called when the filter is performed. The following code shows how to implement filtering in the event aggregator.

C#
Copy Code
public NotificationViewModel()
{
    EventAggregator.Default.Subscribe<MailNotificationEvent, Mail>(OnMailReceived, SubscribeOptions.Default, FilterMail);
}

public bool FilterMail(Mail mail)
{
    return !mail.IsJunk;
}

 

See Also

Reference