Andrej Tozon's blog

In the Attic


Silverlight, Prism EventAggregator and “lost events”

I’ve just started discovering Prism, mainly as a tool to help me use the MVVM with my apps. That said, by now, Prism proved itself with:

  • Support for Commanding
  • EventAggregator
  • Unity integration
  • Targeting both WPF and Silverlight

EventAggregator is great for inter-VM communication, but only when subscribing VM(s) is/are alive (instantiated) when publishing VM publishes the event. I may be wrong here (please somebody correct me), but I haven’t found a way for a newly instantiated subscriber VM get to already broadcasted event, which was published before the instantiation. The example here would be a new dialog window, with its VM wanting the last value that parent’s VM published before dialog was created (a selected ListBox value, for example). Sure, the publisher could publish the same event again after the dialog is created, but this would confuse things up because there may be other listeners subscribed to it and perhaps wouldn’t know how to handle the exact same event.

To solve this issue, I created a new class, deriving from the CompositePresentationEvent<T> and called it CachingCompositePresentationEvent<T>. The implementation is simple:

public class CachingCompositePresentationEvent<T> : CompositePresentationEvent<T>
    public bool HasValue { get; private set; }

    private T lastPayload;
    public T LastPayload
            if (!HasValue)
                throw new InvalidOperationException();
            return lastPayload; 
        private set
            lastPayload = value;
            HasValue = true;

    public override void Publish(T payload)
        LastPayload = payload;

The HasValue will return true when at least one event was published at the time, and LastPayload will return the payload, included in the last published event.

If the event is declared as:

public class MyCachingEvent : CachingCompositePresentationEvent<int> { }

… then getting to its value would be:

MyCachingEvent ev = aggregator.GetEvent<MyCachingEvent>();
if (ev.HasValue)
    int value = ev.LastPayload;

This is the basics, there's plenty of room for improvement - like adding a Clear() method to clear the last payload value or clear it automatically on the first LastPayload read - just to clear the memory, when payload types aren’t simple/small.

Shout it