6
votes

I am having trouble with the prism event aggregator. If I subscribe to, and publish an event in the same module it works fine. Like this -

public class InfrastructureModule : IModule
{
    private IEventAggregator eventAggregator;

    public InfrastructureModule(IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
        eventAggregator.GetEvent<TestEvent>().Subscribe(TestSub);
    }

    public void Initialize()
    {
        eventAggregator.GetEvent<TestEvent>().Publish("Infrastructure module");
    }

    private void TestSub(string s)
    {
        MessageBox.Show(s);
    }
}

However if I subscribe to the event in another module nothing happens when eventAggregator.GetEvent().Publish() is called -

public class OtherModule : IModule
{
    private IEventAggregator eventAggregator;

    public OtherModule (IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
    }

    public void Initialize()
    {
        eventAggregator.GetEvent<TestEvent>().Publish("Other module");
    }
}

The Infrastructure module is registered first so the problem is not that OtherModule is publishing an event before there is a subscriber. Any ideas whats going wrong?

Edit: Here is where I am registering the modules

class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return new Shell();
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();

        App.Current.MainWindow = (Window)this.Shell;
        App.Current.MainWindow.Show();
    }

    protected override void ConfigureModuleCatalog()
    {
        base.ConfigureModuleCatalog();

        ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;

        // Infrastructure module
        moduleCatalog.AddModule(typeof(Infrastructure.InfrastructureModule));


        moduleCatalog.AddModule(typeof(Other.OtherModule));
    }
}
1
Registration is one thing, instantiation is another. Can you show us where your modules are instantiated?Louis Kottmann
As Baboon said - order of instantion of modules (you can read - calling their Initialize() methods) can be different from registration order. Can you add Debug.WriteLine("ModuleName") to both Initialize method and look at debug output - what is real order of initialization?chopikadze
Let me rephrase: can you show us where you call new InfrastructureModule() and new OtherModule() ? (or where you resolve them using Unity)Louis Kottmann
They are being initialized in the correct order. I have breakpoints in the Initialize methods of both classes.Jim_CS
When I set keepSubscriberReferenceAlive to true it works - eventAggregator.GetEvent<TestEvent>().Subscribe(TestSub, true) ...Do I have to do anything extra if I use KeepSubscriberReferenceAlive, the docs give the impression that I need to garbage collect something if I set this value to true?Jim_CS

1 Answers

8
votes

Based on the comments of the OP, the objects are instantiated then destroyed right after.
This makes the Publish("OtherModule"); code do nothing, because the listener was destroyed.

Now indeed, if you set KeepSubscriberReferenceAlive to true,
it will work because your EventAggregator will keep a reference to the subscriber object (InfrastructureModule).
That is not ideal, basically you went from using a Weak Event Pattern where you don't risk memory leaks,
to having to handle objects lifetime and thus risk memory leaks just like a regular .NET event.

Don't get me wrong, I'm not saying you absolutely shouldn't use KeepSubscriberReferenceAlive, but it should only be used on rare occasions.

That being said, your test case is an odd scenario: the Bootstrapper will call Initialize on every Module you define, and then your shell does not hold those modules. Since nobody holds those Modules, they're destroyed.

The "normal" usage for Initialize, is to inject the module that is being initialized into the Shell (or any other UserControl), and it makes sense: you don't want to initialize something you will not use.