ExportFactory<T> and ComponentInitializer.SatisfyImports

Topics: Prism v4 - WPF 4
Jun 30, 2011 at 5:13 PM

I'm running into a bit of an issue here.

.NET 4's MEF does not support ExportFactor<T> or ComponentInitializer for the desktop version. So I downloaded Glenn Block's solution (binary) and referenced it to my project. The project compiles, but I always get issues:

1) If I use the ComponentInitializer.SatisfyImports(this); statement, my imports are not shared. I noticed this when I tried to use the EventAggregator and found that they were different instances even if I import them with CreationPolicy.Shared.

2) If I use the ExportFactory<T> I get an Import/Export Cardinality Mismatch error. Apparently, it doesn't like it when I Import an ExportFactory: [Import] private ExportFactory<IOrderViewModel> _orderFactory; even though I have my ViewModels exported properly.

 

So, I thought maybe I should use the MEF 2 Preview 3 from the codeplex. This causes issues as well... so I recompile Prism v4 using the Codeplex MEF 2 Preview 3 library... it compiles fine, but I still get the same issues as before, only the output is easier to read.

 

I'm really lost. How can I export non-shared instances of a ViewModel that needs to contain the single instance of the EventAggregator? Right now I have some hacky workaround where I import shared instances and call a "Reset()" method on them which resets all the variables... problem is that they are still the same instance. If I don't want the same instance I either run into the issue that I can't use any MEF Imports in the class (because I'm doing new()) or even if I do and use the ComponentInitializer I get different instances imported. Is there any working solution to get the following working:

public class Foo : NotificationObject, IPartImportsSatisfiedNotification
{
    [Import] private IEventAggregator _ea;
    private ObservableCollection<IOrderViewModel> _orders = new ObservableCollection<IOrderViewModel>();

    //From an event
    public void AddOrder(IOrderViewModel order)
    {
        _orders.Add(order);
    }

    public void OnImportsSatisfied()
    {
        //Subscribe to events
    }    
}

public class OrderViewModel : NotificationObject, IPartImportsSatisfiedNotification,  IOrderViewModel
{
    [Import] private IEventAggregator _ea;

    public void DoEvent() { ... }

    public void OnImportsSatisfied()
    {
        //Subscribe to events
    }    
}

public class BarViewModel : NotificationObject
{
    [Import] private IEventAggregator _ea;

    //Somewhere in code - Publishes an Event to add orders and to DoEvent()s.
}

Jun 30, 2011 at 6:31 PM

Hi,

Based on my understanding of your scenario, one possible way to avoid obtaining a new instance of the EventAggregator could be subscribing using strong references.

This concept is explained in the Subscribing Events section, specifically here from Chapter 9: Communicating Between Loosely Coupled Components

On the other hand, you import your dependencies in the ctor of your view models ensuring the injection of your composable parts. For example, like this:

public class OrderViewModel : NotificationObject, IOrderViewModel
{
    [ImportingConstructor]
    public OrderViewModel(IEventAggregator eventAggregator)
    {
        …
        eventAggregator.GetEvent<….>().Subscribe(…)
    }
    
    public void DoEvent() { ... }   
}

Take into account that if you subscribe using strong references, you will have to manually unsubscribes if it no longer wants to receive events.

Thanks,

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic