Send objects from one view model to another view model as argument of constructor [MEF, Caliburn.Micro, Abstract Factory Pattern]

Dec 17, 2010 at 9:14 PM

Hi I create view-models from shell-view-model with abstract factory pattern. I need inject in view-models class from external assembly. On injection I use MEF. Problem is imported classes in view-models are null. As MVVM framework I use Caliburn.Micro.

Shell-view-model:

public interface IViewModelFactory
{
  ILogOnViewModel CreateLogOnViewModel(IShellViewModel shellViewModel);
  IMessengerViewModel CreateMessengerViewModel(IShellViewModel shellViewModel);
}

[Export(typeof(IViewModelFactory))]
public class DefaulFactoryViewModel : IViewModelFactory
{
  #region Implementation of IViewModelFactory

  public ILogOnViewModel CreateLogOnViewModel(IShellViewModel shellViewModel)
  {
    return new LogOnViewModel(shellViewModel);
  }

  public IMessengerViewModel CreateMessengerViewModel(IShellViewModel shellViewModel, PokecAccount account)
  {
    return new MessengerViewModel(shellViewModel, account);
  }

  #endregion
}


public interface IShellViewModel
{
  void ShowLogOnView();
  void ShowMessengerView(PokecAccount account);
}

[Export(typeof(IShellViewModel))]
public class ShellViewModel : Conductor<IScreen>, IShellViewModel
{

  private readonly IViewModelFactory _factory;

  [ImportingConstructor]
  public ShellViewModel(IViewModelFactory factory)
  {
    _factory = factory;
    ShowLogOnView();
  }

  public void ShowLogOnView()
  {
    var model = _factory.CreateLogOnViewModel(this);
    // var model = IoC.Get<LogOnViewModel>();
    ActivateItem(model);
  }

  public void ShowMessengerView(PokecAccount account)
  {
    var model = _factory.CreateMessengerViewModel(this,account);
    ActivateItem(model);
  }
}

View-model:

public class LogOnViewModel : Screen, ILogOnViewModel
{
  [Import]//inject class from external assembly, 
  private IPokecConnection _pokecConn;//after creation of LogOnViewModel is still null

  private PokecAccount _account;

  private readonly IShellViewModel _shellViewModel = null;

  private User _user = null;

  public LogOnViewModel(IShellViewModel shellViewModel)
  {

    _shellViewModel = shellViewModel;

    _user = new User();

    _account = new PokecAccount();
  }

  public void CreateNewViewModel
  {
    //create new view model and pass object _account to the constructor of MessengerViewModel
    _shellViewModel.ShowMessengerView(_account)
  }
}

MEF BOOTSTRAPER CLASS:

 public class MefBootStrapper : Bootstrapper<IShellViewModel>
  {
  #region Fields
  private CompositionContainer _container;
  #endregion

  #region Overrides
  protected override void Configure()
  { // configure container
  #if SILVERLIGHT
    _container = CompositionHost.Initialize(
    new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
  #else

    var catalog =
      new AggregateCatalog(
        AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>());

    //add external DLL
    catalog.Catalogs.Add(
      new AssemblyCatalog(string.Format(
        CultureInfo.InvariantCulture, "{0}{1}", System.IO.Directory.GetCurrentDirectory(), @"\Pokec_Toolkit.dll")));

    _container = new CompositionContainer(catalog);
  #endif

    var batch = new CompositionBatch();

    batch.AddExportedValue<IWindowManager>(new WindowManager());
    batch.AddExportedValue<IEventAggregator>(new EventAggregator());
    batch.AddExportedValue(_container);

    _container.Compose(batch);
    _container.SatisfyImportsOnce(this); 
  }

  protected override object GetInstance(Type serviceType, string key)
  {
    string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
    var exports = _container.GetExportedValues<object>(contract);

    if (exports.Count() > 0)
    return exports.First();

    throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
  }

  protected override IEnumerable<object> GetAllInstances(Type serviceType)
  {
    return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
  }

  protected override void BuildUp(object instance)
  {
    _container.SatisfyImportsOnce(instance);
  }
  #endregion
  }

I use abstract factory pattern because I would like send some variable(s) from view-model-1 (LogOnViewModel)  to another view-model-2 as argument of costructor of view-model-2 (MessengerViewModel).

So I have question:

What is the most suitable solution in my case. In LogOnViewModel I create new view-model MessengerViewModel. I need send some object from LogOnViewModel to MessengerViewModel. And close LogOnViewModel.  I thinking about use EventAggregator class.

I am newbie in MVVM, WPF so I like to advise from you. Thank for help.

I found solution, where they call

  _container.SatisfyImportsOnce(); 

but I have MEF in external class, so I don’t know how solve my problem.