0

I use MEF in Caliburn.Micro for export view models classes. I would like use ExportFactory class rather than Export attribute because I try solve same problem as is described here: Object destruction problem with MEF

I try solve this problem, example:

Some view model - WPF window:

[Export(typeof(IChatViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ChatViewModel : Screen, IViewModelIdentity, 
    IChatViewModel, IHandle<Rp>, IHandle<DetailData>
{}

I open chat screen with window manager in some other view model class:

private IWindowManager _windowManager;
var chatScreen = IoC.Get<IChatViewModel>();
_windowManager.Show(chatScreen);

Then I close screen, but object of this class is still alive. I try same problem as is described here: Object destruction problem with MEF

I have view model - it is WPF window

SCENARIO / SOLUTION

I have 3 view models/screen:

  • LogOnViewModel - user control
  • MessengerViewModel - user control
  • ChatViewModel - WPF Window

Code of these view models is here:

//#1 screen - user control
public class LogOnViewModel : Screen, ILogOnViewModel
{
    private IShellViewModel _shell;

    [ImportingConstructor]
    public LogOnViewModel(IShellViewModel shell)
    {
        _shell = shell;
    }

    //....

    //Active #2 screen Messenger screen
     _shell.ShowMessenger(_account);

    //....
}

//#2 screen - user control
public class MessengerViewModel : Screen,IMessengerViewModel
{       
    private IViewModelsControler _viewModelControler;
    private IWindowManager _windowManager;

    [ImportingConstructor]
    public MessengerViewModel(IViewModelsControler viewModelControler, IWindowManager windowManager)
    {
        _windowManager = windowManager;
        _viewModelControler = viewModelControler;

    }

    //...

    //Open #3 sceen - WPF window
    var vindow = _viewModelControler.CreateChatViewModel();
    _windowManager.Show(window);

    //...
}

//#3 screen - WPF window
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ChatViewModel : Screen, IChatViewModel
{

}

My shell look like this:

  //SHELL is WPF window  
    [Export(typeof(IShellViewModel))]
    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShellViewModel
    {
        [Import]
        public IViewModelsControler ViewModelControler{ get; set;}

        protected override void OnInitialize()
        {
            ShowLogOn();
            base.OnInitialize();
        }

        public void ShowLogOn()
        {
            //var vm = IoC.Get<ILogOnViewModel>();
            var vm = ViewModelControler.CreateLogOnViewModel();
            ActivateItem(vm);
        }

        public void ShowMessenger(Account account)
        {
            ActiveItem.Deactivate(true);
            //var vm = IoC.Get<IMessengerViewModel>();
            var vm = ViewModelControler.CreateMessengerViewModel();
            vm.Account = account;
            ActivateItem(vm);
        }

    }

I would like use ExportFactory class for creation view models class. I try implement same logic as here: http://mef.codeplex.com/wikipage?title=PartCreator.

So I create own controler for creation view models classes:

Here ist it:

public  interface IViewModelsControler
{
    ILogOnViewModel CreateLogOnViewModel();
    IMessengerViewModel CreateMessengerViewModel();
    IChatViewModel CreatChatViewModel();
}

[Export(typeof(IViewModelsControler))]
public class ViewModelsControler:IViewModelsControler
{
    [Import]
    public ExportFactory<ILogOnViewModel> LogOnViewFactory { get; set; }

    public  ILogOnViewModel CreateLogOnViewModel()
    {
        return LogOnViewFactory.CreateExport().Value;
    }

    [Import]
    public ExportFactory<IMessengerViewModel> MessengerViewFactory { get; set; }

    public IMessengerViewModel CreateMessengerViewModel()
    {
        return MessengerViewFactory.CreateExport().Value;
    }

    [Import]
    public ExportFactory<IChatViewModel> ChatViewFactory { get; set; }

    public IChatViewModel CreatChatViewModel()
    {
        return ChatViewFactory.CreateExport().Value;
    }
}

I import ViewModelsControler class in these classes:

  • ShellViewModel
  • MessengerViewModel

And would like method of class ViewModelsControler on creation view models class. - List item

I don’t know what I do bad, if I try compile this code a I get this error:

Could not locate any instances of contract Spirit.ViewModels.IShellViewModel. Staktrace: at Spirit.BootStraper.MefBootStrapper.GetInstance(Type serviceType, String key) in C:\Users\Jan\Documents\Visual Studio 2010\Projects\C#\Pokec_Messenger\ver.beta\Pokec__Messenger\Spirit_Caliburn_Micro_v1.0\BootStraper\MefBootStrapper.cs:line 59 at Caliburn.Micro.IoC.GetT in C:\Users\Jan\Documents\Visual Studio 2010\Projects\C#\Pokec_Messenger\ver.beta\Pokec__Messenger\Caliburn_Micro_Completed\CaliburnMicro\src\Caliburn.Micro.Silverlight\IoC.cs:line 33 at Caliburn.Micro.Bootstrapper`1.DisplayRootView() in C:\Users\Jan\Documents\Visual Studio 2010\Projects\C#\Pokec_Messenger\ver.beta\Pokec__Messenger\Caliburn_Micro_Completed\CaliburnMicro\src\Caliburn.Micro.Silverlight\Bootstrapper.cs:line 175 at Caliburn.Micro.Bootstrapper.OnStartup(Object sender, StartupEventArgs e) in C:\Users\Jan\Documents\Visual Studio 2010\Projects\C#\Pokec_Messenger\ver.beta\Pokec__Messenger\Caliburn_Micro_Completed\CaliburnMicro\src\Caliburn.Micro.Silverlight\Bootstrapper.cs:line 128 at System.Windows.Application.OnStartup(StartupEventArgs e) at System.Windows.Application.<.ctor>b__1(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

If I use Export attribute on creation view model class, it works good.

Something like this:

[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen,ILogOnViewModel
{}

And shell:

   [Export(typeof(IShellViewModel))]
    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShellViewModel
    {
        protected override void OnInitialize()
        {
            ShowLogOn();
            base.OnInitialize();
        }

        public void ShowLogOn()
        {
            var vm = IoC.Get<ILogOnViewModel>();
            //var vm = _viewModelControler.CreateLogOnViewModel();
            ActivateItem(vm);
        }

        public void ShowMessenger(Account account)
        {
            ActiveItem.Deactivate(true);
            var vm = IoC.Get<IMessengerViewModel>();
            //var vm = _viewModelControler.CreateMessengerViewModel();
            vm.Account = account;
            ActivateItem(vm);
        }

    }

Where can be problem? In MEF boostraper class? I use clasic MEF boostrape: http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/caliburn-micro-soup-to-nuts-pt-2-customizing-the-bootstrapper.aspx

Thank for advice, your time and help.

Community
  • 1
  • 1

1 Answers1

1

You still need exports on the classes you want to export. Using ExportFactory allows you to create multiple instances, but it doesn't work if you don't have an export attribute on the thing you want to create instances of.

Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
  • Hello Mr. Plaisted, thank you for explanetion. I have one question its possible call Dispose method on chatWindow object. Object is created with ExportFactory as: var chatScreen = ViewModelControler.CreatChatViewModel(); –  Jan 04 '11 at 18:58