How to utilise Event aggregator in MEF?
Asked Answered
M

4

6

I am running the latest PRISM 4.2. Unfortunately the Event Aggregator tutorial in the documentation is driven via Unity instead of MEF. And I can't get it running under MEF.

App.xaml.cs

 public partial class App : Application
    {
        [Import]
        public IEventAggregator eventAggregator;

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            Bootstrapper bootstrapper = new Bootstrapper();
            bootstrapper.Run();
        }
    }

Bootstrapper.cs

public class Bootstrapper : MefBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return new MainWindow();
        }

        protected override void InitializeShell()
        {
            base.InitializeShell();
            App.Current.MainWindow = (Window)Shell;
            App.Current.MainWindow.Show();
        }

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

            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly));
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            ModuleCatalog moduleCatalog = new ModuleCatalog();

            return moduleCatalog;
        }

    }

MainWindow.xaml.cs

public partial class MainWindow : Window, IView
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel();
        }
    }

MainViewModel.cs:

[ModuleExport(typeof(MainViewModel))]
    public class MainViewModel : BindableBase, IServiceCallback
    {
        [Import]
        public IEventAggregator eventAggregator;

        [ImportingConstructor]
        public MainViewModel()
        {            
            eventAggregator.GetEvent<AppExitEvent>().Publish("");

        }
     }

Despite the [import] the event aggregator is always null both in App.xaml.cs and in MainViewModel. Why is that?
The second question is do I have to export my Viewmodels as a module (as I did above) to use an even aggregator inside them?

UPDATE:

Proof that latest version of PRISM doesn't support ComposeExportedValue anymore.

enter image description here

'System.ComponentModel.Composition.Hosting.CompositionContainer' does not contain a definition for 'ComposeExportedValue' and no extension method ...

Monacid answered 21/2, 2014 at 19:23 Comment(0)
P
7

The solution to this would be what SchubertJ replied on your same question at CodePlex:

As a deeper analyisis, the Import attribute on Properties would not be resolved until the constructor finishes. That is why you would need to inject the EventAggregator dependency through the constructor as a parameter if this dependency would be used on the constructor implementation.

Therefore, if you would like to use the EventAggregator dependency on the ViewModel constructor, you should use [ImportConstructor] attribute instead, and ask the container for the EventAggregator instance by retreiving it as a parameter:

public class MainViewModel
{
    private readonly IEventAggregator eventAggregator;

    [ImportingConstructor]
    public MainViewModel(IEventAggregator eventAggregator)
    {
       this.eventAggregator = eventAggregator;

       this.eventAggregator.GetEvent<MyEvent>().Publish("");
    }
}

You may find more related information regarding both import alternatives in the following post:

I hope this helped you, Regards.

Pistil answered 24/2, 2014 at 15:4 Comment(2)
Glad to hear that. However, do you have any suggesions for my answer that haven't made you upvote it? Highlights, poor issue explanation perhaps? Thank you.Pistil
Done. Accepted answer as well. ;)Monacid
S
1

In your bootstrapper class have this method :

protected override void ConfigureContainer()
{
     base.ConfigureContainer();
     Container.ComposeExportedValue(new EventAggregator());
}

You should look at this article as it is answer both your first and second question in better details. http://www.gonetdotnet.info/posts/wpf-articles/wpf-module-communication

Update:

If you create a class as below it will match your export with your import.

public class EventAggProvider
   {
     [Export(typeof(IEventAggregator))]
     public IEventAggregator eventAggregator { get { return new EventAggregator(); } }
   }
Stipe answered 21/2, 2014 at 19:29 Comment(6)
where is your articleJeconiah
Are you sure you don't mean the ConfigureAggregateCatalog instead of ConfigureContainer? I thought the former handles the MEF consumable parts within the application.Monacid
your article has nothing to do with MEF and eventagregatorJeconiah
@K.B read the article, the author is using MEF, and the way he uses it answers both questions here.Stipe
@TYY, I just tried what you suggested, it says ComposeExportedValue not found. In the latest version these things seems to have changed. I worked on that article 3 hours ago. I couldn't get it working either. In StackOverflow answers should have a code suggestion instead of further articles. ;) ThanksMonacid
@Hooman I dont have the latest Prism, but I am also able to do this and it works. Look at my updated answer and see if that gets you going. I can't vouch that it is the correct route to follow thoughStipe
S
1

It is a little late, but there is also a solution for the case in which you want the EventAggregator gets injected in property. Implement 'IPartImportsSatisfiedNotification' and use the eventaggregator in 'OnImportsSatisfied' method.

public class MainViewModel : BindableBase,  IPartImportsSatisfiedNotification
{
    [Import]
    public IEventAggregator eventAggregator;

    public void OnImportsSatisfied()
    {
        eventAggregator.GetEvent<AppExitEvent>().Publish("");
    }
 }
Starspangled answered 3/11, 2016 at 16:46 Comment(0)
J
0

EventAggregator does not depend on MEF or Unity it's design pattern coined by Martin Fowler and it's based on publisher subscriber scenario

try to follow this steps

//this should be in your infrastructure layer

public  static class EventAggregatorHelper
{
  private static IEventAggregator _Current = new EventAggregator();
  public static IEventAggregator Current
  {
    get
    {
      return _Current;
    }
  }
}



The HandleAppExitEvent is a class declared as shown below:

public class AppExitEvent : CompositePresentationEvent<String>
{
} 

and the subscriber would be something like this:

in your MainWindow.xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel();  
 //In this case the HandleAppExitEvent and the subscriber that deals with this event.                   
 EventAggregatorHelper.Current.GetEvent<AppExitEvent>().   Subscribe(HandleAppExitEvent);  

            }
      //note that this method should be public 

 public void HandleAppExitEvent(string mess)
    {
       if (!String.IsNullOrEmpty(mess))
       {
          //Do whatever you need to do here.
       }
    }

    }
Jeconiah answered 21/2, 2014 at 19:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.