Prism’s IEventAggregator: inheritance doesn’t work as expected

Prism

Microsoft has released a library, Prism, that helps developers build modular WPF applications (I am currently using MEF). Prism’s primary purpose is front-end; it has components that help with views, data-binding, regions, events, etc.

IEventAggregator

Prism exports an interface called IEventAggregator which allows classes within modules to subscribe / unsubscribe and publish certain events. In the example below, a view model imports the event aggregator and subscribes to the composite event with a payload of type ‘MyCustomEvent’:

This is fine and dandy, and works quite well. But I had requirements that made me take an extra step. Enter inheritance – more specifically, interfaces.

My scenario

I have three types of sync events that need to be available to all modules:

  • SyncPullFinishedEvent
  • SyncPushFinishedEvent
  • SyncRefreshFinishedEvent

The three events are different because certain interactions with the application will trigger specific events: i.e. when a user tries to pull new data vs. when a user tries to push existing data. The three events are also similar in some regard because they share some properties. So make an interface, right? Sure… Here is the interface that all those classes will implement:

Certain viewmodels / services care about which specific event was published, whereas others might not care. Here is an example:

  1. I am a viewmodel that controls a sync status view. I behave (look and feel) differently if the user tries to push vs. pull. Sometimes I need to show extra options if a pull resulted in a failure as opposed to a push.
  2. I am a viewmodel that controls a view for data. I behave the same regardless of which sync interaction the user just finished. All I need to know is whether or not I should refresh my data.

Inheritance is great

Inheritance allows us to simplify the viewmodel from the second (2) scenario listed above. Instead of subscribing to the three different events, we can instead subscribe to one. The viewmodel from the first (1) scenario listed above still wants to subscribe to the events separately:

The first one is a bit cleaner, and we would still be listening for publications of all three sync finish events…

WRONG!!

Prism’s implementation of IEventAggregator does not follow object oriented principles

Unfortunately the event aggregator does not behave this way because each event must be strongly typed. In the above code example, if a service published the ‘SyncPullFinishedEvent’, the ‘MyDataViewModel’ (scenario 2) would never know. However, because the ‘MySyncViewModel’ (scenario 1) explicitly subscribed to each event type it would know that the event was published.

If we wanted our ‘MyDataViewModel’ to listen to the events in a generic fashion, we would still have to subscribe to each event that implements the ‘ISyncFinishedEvent’. You could perhaps use reflection to determine all classes that implement this interface at run-time, and then keep a dictionary of those types and their subscriptions (just thinking that makes me feel sick). In my opinion, this is bad design and makes for unmanageable code.

Posted in Professional Tagged with: , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Subscribe to my Insights via Email

Join 61 other subscribers

%d bloggers like this: