I am working on a WPF app using the MVVM pattern. Additionally, I have been utilizing the Prism Event Aggregator functionality to communicate between view models.
We are using a library of controls and one of the controls we are using (an altered/customized datagrid) has events that the library author has created. For example, when a cell has ended editing...similar to a loss focus. The issue I am facing is that the library control utilizes the code behind instead of the view model for the event method.
I figured I would simply utilize the event aggregator to let the VM know about the event from the code behind. It is not working. My vm uses a simple subscribe in the constructor...
_eventAggregator.GetEvent<AfterLineAmountPaidEvent>().Subscribe(OnLineAmountPaidChanged);
The OnLineAmountPaidChanged method never gets hit.
In the code-behind, I am publishing the event...
_eventAggregator.GetEvent<AfterLineAmountPaidEvent>().Publish(
new AfterLineAmountPaidEventArgs
{
InvoiceLinesSelectedAmount = InvoiceLinesDataGrid.ItemsSource
});
I am wondering if it has to do with the instantiation of the Prism library and the Event Aggregator. In the VM, I am creating it via the constructor...
IEventAggregator eventAggregator
I am extending the VM with a base VM...
: base(eventAggregator, messageDialogService)
I then assign the instantiation to a private that I use as shown in previous code...
private readonly IEventAggregator _eventAggregator;
In the code-behind, I instantiate the event aggregator as follows...
private readonly IEventAggregator _eventAggregator = new EventAggregator();
When I step through the code using breakpoints, I notice that the subscriptions change once the code hits the code-behind from 2 (two) to 0 (zero). This is why I think that it is getting reinstantiated for the app in the code behind with the way I am utilizing the library.
Is there a different/better way to accomplish this communication? Am I instantiating the event aggregator incorrectly?
Any advice is helpful.
Your guess is correct. The problem is you have two
EventAggregatorobjects. Your code is not supposed to instantiate the EventAggregator. It is supposed given to be given to you from Prism. Your code-behind needs to get the same instance ofEventAggregatorthat your view model gets.The nice thing is that you can inject that same
EventAggregatorto the view that goes with your viewmodel the same way that the viewmodel gets it. Via constructor injection. Then pass it along to any other code-bhiend from there.Here's an example. I have a Prism module called my
ExploreModule. Inside the module-derived class my RegisterTypes function looks like this:In my app, the view-model that goes with my
ExploreViewis calledExploreVm. You don't see it being listed here because I use Prism's "view-model-locator" approach. But basically whenever Prism creates myExploreView, it creates anExploreVmto go along with it.This means that I can add any registered-service I want to the constructor of either
ExploreVmorExploreView. IncludingIEventAggregatorSo I edit my
ExploreVmto takeIEventAggregator. Here's the one I use. It addsIEventAggregatoras well another service that I personally created and registered. Since Prism creates this view model for me, it just handes me both services.And I can also edit my
ExploreViewthe same way if I wantYou should have a similar view/view-model pair where you can do the same.
Now if I had some child view/control (not created by Prism) that I needed to get access to
IEventAggregator, then I would expose theIEventAggregatorin a property or use some other way to pass it down. But this Prism-created view/view-model is the entry point.Regardless, the key point is you do not create the EventAggregator. Prism does.