Simplifying PRISM’s EventAggregator

I recently started using PRISM’s EventAggregator for messaging in my WPF applications, however I find the syntax confusing, and hard to remember.

Here’s the default syntax for PRISM’s EventAggregator

// Optional: Create Event "Message"
// Needed for multiple parameters, but not for single parameter
// messages. I prefer using one in most cases because I find
// it makes it easier to read the code
public class TickerSymbolSelectedMessage
{
    public string StockSymbol { get; set; }
}

// Create an Event
public class TickerSymbolSelectedEvent : 
    CompositePresentationEvent<TickerSymbolSelectedMessage>{}

// Subscribe to an Event
eventAggregator.GetEvent<ChangeStockEvent>().Subscribe(ShowNews);

public void ShowNews(TickerSymbolSelectedMessage msg)
{
   // Handle Event
}

// Broadcast an Event
eventAggregator.GetEvent<ChangeStockEvent>().Publish(
    new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0” });

There are a few things that irritate me about this syntax:

  • Needing to call GetEvent() all the time before subscribing/publishing
  • Needing a reference to the EventAggregator anywhere I want to use it
  • Needing to create two classes for an Event: the Event itself and the EventMessage (technically this one is optional if you only have one Parameter, but I like to create it anyways because I find it easier to read)

A large portion of the time I am working small apps which usually have a single purpose, so I wrote myself a simple helper class that gets rid of these annoyances. I’m not sure I’d recommend using this in larger apps since it passes all the events over the same channel, but I find it makes my life with small apps much simpler.

Now I just create the EventMessage, and can use some easy Subscribe/Publish calls anywhere in the application. Simple, easy to remember syntax, no need to pass around an EventAggregator object, and all I have to create is my Event Messages.

// Create the Event Message
public class TickerSymbolSelectedMessage
{
    public string StockSymbol { get; set; }
}

// Subscribe to Events
EventSystem.Subscribe<TickerSymbolSelectedMessage>(ShowNews);

public void ShowNews(TickerSymbolSelectedMessage msg)
{
   // Handle Event
}

// Broadcast Events
EventSystem.Publish<TickerSymbolSelectedMessage>(
    new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0”});

And here’s the EventSystem class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Events;

namespace MyNamespace
{
    /// <summary>
    /// Static EventAggregator
    /// </summary>
    public static class EventSystem
    {
        private static IEventAggregator _current;
        public static IEventAggregator Current
        {
            get
            {
                return _current ?? (_current = new EventAggregator());
            }
        }

        private static CompositePresentationEvent<TEvent> GetEvent<TEvent>()
        {
            return Current.GetEvent<CompositePresentationEvent<TEvent>>();
        }

        public static void Publish<TEvent>()
        {
            Publish<TEvent>(default(TEvent));
        }

        public static void Publish<TEvent>(TEvent @event)
        {
            GetEvent<TEvent>().Publish(@event);
        }

        public static SubscriptionToken Subscribe<TEvent>(Action action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false)
        {
            return Subscribe<TEvent>(e => action(), threadOption, keepSubscriberReferenceAlive);
        }

        public static SubscriptionToken Subscribe<TEvent>(Action<TEvent> action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false, Predicate<TEvent> filter = null)
        {
            return GetEvent<TEvent>().Subscribe(action, threadOption, keepSubscriberReferenceAlive, filter);
        }

        public static void Unsubscribe<TEvent>(SubscriptionToken token)
        {
            GetEvent<TEvent>().Unsubscribe(token);
        }        public static void Unsubscribe<TEvent>(Action<TEvent> subscriber)
        {
            GetEvent<TEvent>().Unsubscribe(subscriber);
        }
    }
}

16 Responses to Simplifying PRISM’s EventAggregator

  1. StepUp says:

    Rachel, you are a superPROGRAMMER!

  2. Kam says:

    Rachel,

    You saved my butt with this. I was having such a hard time wrapping my head around this whole messaging, mediator, eventaggregrator and making any of it work. I implemented it with sending informaiton from edited forms back to my mainviewmodel to refresh it’s data and make it reselect it’s selecteditem. Thanks for the great code and keep it up!

  3. e1dar says:

    Nice example Rachel! I want to share my own wrapper

    public abstract class EventBase : CompositePresentationEvent where TEvent : EventBase, new()
    {
    private static readonly Lazy _eventAggregator
    = new Lazy(ServiceLocator.Current.GetInstance);

    public static TEvent Instance
    {
    get { return _eventAggregator.Value.GetEvent(); }
    }
    }

    class SomeEvent : EventBase { … }

    and call SomeEvent.Instance.Publish(“message”)

    • e1dar says:

      🙂 parser cutted off all generics stuff

      public abstract class EventBase[TEvent, TPayload] : CompositePresentationEvent[TPayload] where TEvent : EventBase, new()
      {
      private static readonly Lazy[IEventAggregator] _eventAggregator
      = new Lazy[IEventAggregator](ServiceLocator.Current.GetInstance[IEventAggregator]);

      public static TEvent Instance
      {
      get { return _eventAggregator.Value.GetEvent[TEvent](); }
      }
      }

  4. Stephan E says:

    Simple, elegant and straight to the point: well done!

  5. Mike Horton says:

    Goofy question but I’m just getting into MVVM and wpf. Where does TickerSymbolSelectedMessagemsg come from?

    • Rachel says:

      Hi Mike,

      Its just a class you create that can be called anything (see the top bit of code).

      You can actually use a basic data type such as a string or an object instead, but I find it easier to understand and maintain the code if I create a class for each of my Message types. That way, I always know what message is getting passed around and I can add extra parameters to it if needed.

      • Mike Horton says:

        Sorry I wasn’t clear. I understand the TickerSymbolSelectedMessage class. What I was trying to figure out was the TickerSymbolSelectedMessagemsg in the pubic void ShowNews(TickerSymbolSelectedMessagemsg) procedure. I tried putting an entry in there and it caused an error. If I removed it my code compiled but my Show procedure was never called after I published the event.

      • Mike Horton says:

        And cancel my reply. I was taking TickerSymbolSelectedMessagemsg literally as one word. Just clued in that there should be a space before msg.

      • Rachel says:

        I see what you’re referring to now, thanks for pointing out that typo =)

  6. retrocoder says:

    I find that my subscription functions (ShowNews in your example) gets called twice. Any ideas why that would be?

    • Rachel says:

      It probably has something to do with how you hooked up the subscription functions. Try posting a question on StackOverflow with a short sample of your code, and someone will probably be able to help you figure out the exact problem 🙂

      • retrocoder says:

        Hello, my problem was down to unity and my classes being created multiple times, hence multiple subscriptions. I’ve now fixed that problem and your code works great for my requirements.

  7. H L says:

    Thank you. This is a big time saver.

  8. Andrewa says:

    I have been searching for days for a solution such as this. You have just made my life wonderfully better.

  9. Aaron B says:

    Thank you for the wrapper. You did a great job on this!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: