Event Aggregator injection confusion

Topics: Prism v4 - WPF 4
Nov 17, 2010 at 8:15 PM

I am not sure if I understanding what is going on when the event aggregator is injected into the constructor.

In TrendLineViewModel.cs I added the following line to the constructor after the GetEvent<>.

var ieventAggregator = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<Microsoft.Practices.Prism.Events.IEventAggregator>();

Both the eventAggregator and ieventAggregator have 1 event each, which makes sense.

Now on my project I have the following code.

[ImportingConstructor]
public ShellViewModel(IEventAggregator eventAggregator)
{
    eventAggregator.GetEvent<LogOnEvent>().Subscribe(this.OnAccountLogOn, ThreadOption.UIThread, true);
    eventAggregator.GetEvent<LogOffEvent>().Subscribe(this.OnAccountLogOff, ThreadOption.UIThread, true);

    var ieventAggregator = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<Microsoft.Practices.Prism.Events.IEventAggregator>();
}

The eventAggregator is showing a count of 2 events while ieventAggregator is showing 0 events.

How is it that the eventAggregator being injected is not the same as the current Instance?
I am using the ported CompositionInitializer code from Silverlight to use in my WPF project, could this be part of the issue?

For some background on what I am doing you can see this post.
http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=234536

Nov 18, 2010 at 3:28 PM

Hi,

There is no similar issues reported so far. I tried to reproduce this scenario and found no issues. I am using the following code in the View-Switching Navigation Quickstart:

[ImportingConstructor]
public InboxView(IEventAggregator eventAggregator)
{
InitializeComponent();
var eventAggregatorTest = eventAggregator.GetEvent<EventAggregatorTest>();
eventAggregatorTest.Subscribe(this.Test1, ThreadOption.UIThread, true);
eventAggregatorTest.Subscribe(this.Test2, ThreadOption.UIThread, true);
var eventAggregatorFromSL = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IEventAggregator>();
var eventAggregatorTestFromSL = eventAggregatorFromSL.GetEvent<EventAggregatorTest>();
}

In the following image you can see my two reference to the EventAggregator:

If you continue experiencing this situation, could you please send a repro sample?

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

Developer
Nov 18, 2010 at 3:53 PM

If you're using CompositionInitializer, you'll need to make sure that, during bootstrapping, you're setting the container the CompositionInitializer knows about by calling CompositionHost.Initialize with the same MEF composition container that Prism is using.

HTH,

-b

Nov 19, 2010 at 5:51 PM

Thanks brumfb,
I was not initializing CompositionHost with the CompositionContainer.

// Bootstrapper.cs
protected override CompositionContainer CreateContainer()
{
    var container = base.CreateContainer();

    CompositionHost.Initialize(container);

    return container;
}

// ShellViewModel.cs
[ImportingConstructor]
public ShellViewModel(IEventAggregator eventAggregator)
{
    if (eventAggregator != null)
    {
        eventAggregator.GetEvent<LogOnEvent>().Subscribe(this.OnAccountLogOn, ThreadOption.UIThread, true);
        eventAggregator.GetEvent<LogOffEvent>().Subscribe(this.OnAccountLogOff, ThreadOption.UIThread, true);
    }

    var ieventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
}

I am not sure if this would be the proper way to do it but this also worked.

// ShellViewModel.cs
[ImportingConstructor]
public ShellViewModel()
{
    var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();

    if (eventAggregator != null)
    {
        eventAggregator.GetEvent<LogOnEvent>().Subscribe(this.OnAccountLogOn, ThreadOption.UIThread, true);
        eventAggregator.GetEvent<LogOffEvent>().Subscribe(this.OnAccountLogOff, ThreadOption.UIThread, true);
    }

    var ieventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
}

Developer
Nov 19, 2010 at 8:02 PM

So there are two things here.  Using the service locator vs. constructor injection can come down to a bit of a preference, but I tend to prefer the explicit dependency you get when it's done through constructor injection. 

With MEF, there is something else to consider regarding using constructor injection.  Using constructor injection in MEF means you can't re-compose the inject contracts/interfaces.  If you wanted this you would need to use property injection. 

HTH,

-b