Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prism Event Aggregation - subscriber not triggered

I'm working on implementing an event aggregation with Prism. I have a few modules, and I want each of them to subscribe to events that tells them when they are requested. I started out doing an all plain example with both subscribed and publisher in the shell. No problems there. Now; when I move the subscribers out to my modules they don't get triggered. What's even more odd is that it actually has worked a few times - all of which I've been pending in a breakpoint. So it seems to me to be some race condition, but I don't understand why.

Assumption made: I don't need to set up the IEventAggregator anywhere - e.g. registering in the IoC container? This is built into Prism such that I only have one instance of the event aggregator, right?

So, the question is basically how/where/when I should set up my subscribers. Is there a specific order on stuff etc? In my simplified example I have one module MyModule. The Bootstrapper will add MyModule to the catalog - making it initialized:

catalog.AddModule(typeof(MyModule));

MyModule will store the aggregator and use this for subscribing to the MyModuleRequestedEvent. It also uses a menu registry to register in the application menu. The idea is that eventually clicking in the menu should trigger the event - notifying MyModule that it has been requested. Then I want it to be MyModule's responsibility to figure out what to do further.

public MyModule(IEventAggregator aggregator, IApplicationMenuRegistry menu)
{
    _applicationMenu = menu;
    _aggregator = aggregator;
}

public void Initialize()
{
    var evnt = _aggregator.GetEvent<MyModuleRequestedEvent>();
    evnt.Subscribe(MyModuleRequested);
    _applicationMenu.RegisterMenuItem("MyModule", evnt);
}

public void MyModuleRequested(bool b)
{
    MessageBox.Show("MyModule requested");
}

Now, I have a button in my shell which will publish this event. The shell gets the same (?) event aggregator when resolved.

public Shell(IEventAggregator aggregator)
{
    InitializeComponent();
    var evnt = aggregator.GetEvent<MyModuleRequestedEvent>();
    EventTriggerButton.Click += (s, e) => evnt.Publish(true);
}

Notes:

  • Have verified that the event is published. Adding a subscriber in the shell too will make this subscriber receive the event.
  • Again; the subscriber in MyModule isn't triggered. However, it has - strangely - been on a few occasions.
  • I don't use the input to the event. It seemed like you needed to have some input-type, so I just went with a dummy bool. Can I get rid of this..?
like image 560
stiank81 Avatar asked Nov 27 '09 21:11

stiank81


People also ask

How do you use event aggregator prism?

To use it in any class (that's registered with Prism's IoC), all you need to do is ask for an instance of IEventAggregator in the constructor. Prism will automatically pass an instance of its EventAggregator when the ViewModel is constructed. There's no need to register or set up anything else.

What is EventAggregator in Prism?

In the Prism Library, the EventAggregator allows subscribers or publishers to locate a specific EventBase . The event aggregator also allows for multiple publishers and multiple subscribers, as shown in the following illustration.

What is EventAggregator?

An Event Aggregator acts as a single source of events for many objects. It registers for all the events of the many objects allowing clients to register with just the aggregator.


2 Answers

The Prism Event Aggregator uses Weak References to link to the events. This is to prevent memory leaks from event handlers.

Once a module initializer has been run it's disposed of, so your event handler is being destroyed before the event is being fired. You can tell Prism to keep the event handler around by using an overload of Subscribe.

evnt.Subscribe(MyModuleRequested, true);

As a pattern, I tend to put any event subscribers in a separate class, and call that class from the modules Initialize method. That way the events stay alive but separate while the module is still destroyed.

like image 100
Cameron MacFarland Avatar answered Nov 12 '22 00:11

Cameron MacFarland


So, I just got a theory, but no time to test it right now.. Will do tomorrow.

Question: Will adding modules to the ModuleCatalogue keep them alive? I assumed it would. Hence - the MyModule should stay alive - and then will be triggered when the event is published.

protected override IModuleCatalog GetModuleCatalog()
{
    var catalog = new ModuleCatalog();
    catalog.AddModule(typeof(MyModule));
    return catalog;
}

However, if this doesn't keep the module alive it is obvious that it will have a hard time respond to the event. The module-object dies, but it doesn't unsubscribe - hence I'll see the subscriber in the EventAggregator list, but the subscriber isn't around anymore. Also; I mentioned that I it does in fact work occasionally - which would be the case if the garbage collector didn't have time to take out the trash before the event is triggered.

Does this sound like the case? If so - I haven't thought of a solution yet so you're welcome to suggest one in a different reply-thread..

So; what is the ModuleCataloge anyway? Just a list kept for Initialization and then thrown away?

like image 2
stiank81 Avatar answered Nov 12 '22 00:11

stiank81