Skip to content

The EventAggregator

ImminentFate edited this page Apr 1, 2018 · 7 revisions

The EventAggregator is a decentralised, weakly-binding, publish/subscribe-based event manager.

Publishers and Subscribers

Subscribers

Subscribers interesting in a particular event can tell the IEventAggregator of their interest, and will be notified whenever a publisher publishes that particular event to the IEventAggregator.

Events are classes - do whatever you want with them. For example:

C# VB.NET
class MyEvent { 
 
  // Do something 
 
}
Class MyEvent
 
  ' Do Something
 
End Class

Subscribers must implement IHandle<T>, where T is the event type they are interested in receiving (they can of course implement multiple IHandle<T>'s for multiple T's). They must then get hold of an instance of the IEventAggregator, and subscribe themselves, for example:

C# VB.NET
class Subscriber : IHandle<MyEvent>, IHandle<MyOtherEvent>
{
   public Subscriber(IEventAggregator eventAggregator)
   {
      eventAggregator.Subscribe(this);
   }
 
   public void Handle(MyEvent message)
   {
      // ...
   }
 
   public void Handle(MyOtherEvent message)
   {
      // ...
   }
}
Class Subscriber : Implements IHandle(Of MyEvent)
 
  Public Sub New(ByRef eventAggregator as IEventAggregator)
  eventAggregator.Subscribe(Me)
  End Sub
 
  Public Sub Handle(message as MyEvent) Implements IHandle(Of MyEvent).Handle
  ' ...
  End Sub
 
  Public Sub Handle(message as MyOtherEvent) Implements IHandle(Of MyOtherEvent).Handle
  ' ...
  End Sub
 
End Class

For VB.NET users, the Sub New() passing the eventAggregator by reference will probably fail across namespaces, and can be irritating to have to define with each new subscriber. Thus, it may be easier to define your eventAggregator in a global module, then subscribe directly to it instead of passing its reference along to each new ViewModel you call.

Module Global
  Public eventAggregator as IEventAggregator
End Module

Class Subscriber : Implements IHandle(Of MyEvent)

  Public Sub New()
  Global.eventAggregator.Subscribe(Me)
  End Sub
  
  'Public Sub Handle...

End Class

Make sure to keep the namespace for the module blank, so that it can be used throughout the program.

Publishers

Publishers must also get an instance of the IEventAggregator, but they don't need to subscribe themselves - they only need to call IEventAggregator.Publish every time they want to publish an event, for example:

 

C# VB.NET
class Publisher
{
   private IEventAggregator eventAggregator;
   public Publisher(IEventAggregator eventAggregator)
   {
      this.eventAggregator = eventAggregator;
   }
 
   public void PublishEvent()
   {
      this.eventAggregator.Publish(new MyEvent());
   }
}
Class Publisher 
 
  Dim eventAggregator as IEventAggregator
 
  Public Sub New(ByRef eventAggregator as IEventAggregator)
    Me.eventAggregator = eventAggregator
  End Sub
 
  Public Sub PublishEvent()
  Me.eventAggregator.Publish(New MyEvent())
  End Sub
 
End Class

Again, for VB.NET users, if you've set up the global module then you don't need to pass the eventAggregator to the Publisher. You can just publish directly to the global eventAggregator;

Class Publisher

  Public Sub PublishEvent()
  Global.eventAggregator.Publish(New MyEvent())
  End Sub
  
End Class

Unsubscribing and weak binding

Because the IEventAggregator is weakly binding, subscribers don't need to unsubscribe themselves - the IEventAggregator won't retain them. It is however possible for a subscriber to unsubscribe itself if it wants - call  

C# VB.NET
IEventAggregator.Unsubscribe(this);
IEventAggregator.UnSubscribe(Me)

Publishing synchronously and asynchronously

The default IEventAggregator.Publish method publishes the event synchronously. You can also call PublishOnUIThread to dispatch asynchronously to the UI thread, or PublishWithDispatcher and pass any action you want to act as the dispatcher (this can be useful if writing your own methods on IEventAggregator).

Channels

Subscribers can listen to particular channels, and publishers can publish events to particular channels. If an event is published to a particular channel, only subscribers who have subscribed to that channel will receive that event. This can be useful if the same message type is used in several different contexts.

Channels are strings, and so allow loose coupling between subscribers to a channel, and publishers to that channel.

By default, Subscribe() will subscribe the subscriber to a single channel, EventAggregator.DefaultChannel. Similarly, Publish() (and all variants thereof) will publish events to that same default channel. However, you can specify your own channel(s) if you want....

Subscribing to channels

To subscribe to a particular channel, pass it as a parameter to Subscribe: eventAggregator.Subscribe(this, "ChannelA"). You can also subscribe to multiple channels: eventAggregator.Subscribe(this, "ChannelA", "ChannelB").

In both of these cases, you will not be subscribed to EventAggregator.DefaultChannel - only to the channels listed. You will only receive events that were pushed to "ChannelA" or "ChannelB".

Publishing to channels

To publish to a particular channel, pass it as a parameter to Publish: eventAggregator.Publish(message, "ChannelA"), or eventAggregator.PublishOnUIThread(message, "ChannelA", "ChannelB"), etc. As with subscribing above, the event will be published to all of the channels named, and not to the default channel.

Unsubscribing from channels

To unsubscribe from a channel, pass it to Unsubscribe: eventAggregator.Unsubscribe(this, "ChannelA"). You will remain subscribed to any other channels you were previously subscribed to, and have not unsubscribed from.

Calling eventAggregator.Unsubscribe(this) will unsubscribe you from all channels.

Using your own IoC container

If you're using StyletIoC with the default Bootstrapper<TRootViewModel>, you don't need to worry about this - the EventAggregator is set up correctly by default.

If you're using another IoC container, however, you need to make sure that the EventAggregator is registered as a singleton service to the interface IEventAggregator - there must be only one instance of the EventAggregator created, ever, and this once instance must be returned every time it is requested.

Clone this wiki locally