Switching between ViewModels using IoC in a MVVM WPF application

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite
1












I have a project that uses Caliburn.Micro to implement the MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))]. IScreen is defined in Caliburn.Micro.



In my BootStrapper file I have set up MEF like so:



private CompositionContainer container;

protected override void Configure()


//Set up MEF

container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

var batch = new CompositionBatch();

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

...



Now, I show the first ViewModel using:



protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();


All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.



An example of a ViewModel is:




[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>

[ImportingConstructor]
public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)




...




So far so good.



Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?



Here is what I am doing now. I am using ExportFactory of MEF. I have a class that holds a collection of ExportFactory, one for each IScreen.



[Export(typeof(IScreenFactory))]
class ScreenFactory : IScreenFactory

private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary get; set;
private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection get; set;
private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx get; set;

[ImportingConstructor]
public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)

_screenfactoryCollection = screenList;
_reportfactoryCollection = reportsList;


public IScreen GetScreen(Type t)

if (_screenDictionary == null)

PopulateScreenDictionary(_screenfactoryCollection);


_currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
return _currentScreenLifeTimeCtx.Value;


private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)

_screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);


public void DisposeCurrentScreenContext()

_currentScreenLifeTimeCtx?.Dispose();


public void Dispose()

DisposeCurrentScreenContext();




Whenever I need a new instance of a ViewModel, I just publish a message using the EventAggregator and the MainViewModel does this:



DeactivateItem(ActiveItem, true);
_vmFactory.DisposeCurrentScreenContext();
ActivateItem(_vmFactory.GetScreen(NextViewModelName));


This CANNOT be the normal way to do so. Also, this adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30. That is because of how ExportFactory is messily implemented in the ScreenFactory class.



I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.







share|improve this question



























    up vote
    2
    down vote

    favorite
    1












    I have a project that uses Caliburn.Micro to implement the MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))]. IScreen is defined in Caliburn.Micro.



    In my BootStrapper file I have set up MEF like so:



    private CompositionContainer container;

    protected override void Configure()


    //Set up MEF

    container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

    var batch = new CompositionBatch();

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

    ...



    Now, I show the first ViewModel using:



    protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();


    All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.



    An example of a ViewModel is:




    [PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
    sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>

    [ImportingConstructor]
    public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)




    ...




    So far so good.



    Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?



    Here is what I am doing now. I am using ExportFactory of MEF. I have a class that holds a collection of ExportFactory, one for each IScreen.



    [Export(typeof(IScreenFactory))]
    class ScreenFactory : IScreenFactory

    private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary get; set;
    private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection get; set;
    private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx get; set;

    [ImportingConstructor]
    public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)

    _screenfactoryCollection = screenList;
    _reportfactoryCollection = reportsList;


    public IScreen GetScreen(Type t)

    if (_screenDictionary == null)

    PopulateScreenDictionary(_screenfactoryCollection);


    _currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
    return _currentScreenLifeTimeCtx.Value;


    private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)

    _screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);


    public void DisposeCurrentScreenContext()

    _currentScreenLifeTimeCtx?.Dispose();


    public void Dispose()

    DisposeCurrentScreenContext();




    Whenever I need a new instance of a ViewModel, I just publish a message using the EventAggregator and the MainViewModel does this:



    DeactivateItem(ActiveItem, true);
    _vmFactory.DisposeCurrentScreenContext();
    ActivateItem(_vmFactory.GetScreen(NextViewModelName));


    This CANNOT be the normal way to do so. Also, this adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30. That is because of how ExportFactory is messily implemented in the ScreenFactory class.



    I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.







    share|improve this question























      up vote
      2
      down vote

      favorite
      1









      up vote
      2
      down vote

      favorite
      1






      1





      I have a project that uses Caliburn.Micro to implement the MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))]. IScreen is defined in Caliburn.Micro.



      In my BootStrapper file I have set up MEF like so:



      private CompositionContainer container;

      protected override void Configure()


      //Set up MEF

      container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

      var batch = new CompositionBatch();

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

      ...



      Now, I show the first ViewModel using:



      protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();


      All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.



      An example of a ViewModel is:




      [PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
      sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>

      [ImportingConstructor]
      public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)




      ...




      So far so good.



      Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?



      Here is what I am doing now. I am using ExportFactory of MEF. I have a class that holds a collection of ExportFactory, one for each IScreen.



      [Export(typeof(IScreenFactory))]
      class ScreenFactory : IScreenFactory

      private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary get; set;
      private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection get; set;
      private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx get; set;

      [ImportingConstructor]
      public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)

      _screenfactoryCollection = screenList;
      _reportfactoryCollection = reportsList;


      public IScreen GetScreen(Type t)

      if (_screenDictionary == null)

      PopulateScreenDictionary(_screenfactoryCollection);


      _currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
      return _currentScreenLifeTimeCtx.Value;


      private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)

      _screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);


      public void DisposeCurrentScreenContext()

      _currentScreenLifeTimeCtx?.Dispose();


      public void Dispose()

      DisposeCurrentScreenContext();




      Whenever I need a new instance of a ViewModel, I just publish a message using the EventAggregator and the MainViewModel does this:



      DeactivateItem(ActiveItem, true);
      _vmFactory.DisposeCurrentScreenContext();
      ActivateItem(_vmFactory.GetScreen(NextViewModelName));


      This CANNOT be the normal way to do so. Also, this adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30. That is because of how ExportFactory is messily implemented in the ScreenFactory class.



      I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.







      share|improve this question













      I have a project that uses Caliburn.Micro to implement the MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))]. IScreen is defined in Caliburn.Micro.



      In my BootStrapper file I have set up MEF like so:



      private CompositionContainer container;

      protected override void Configure()


      //Set up MEF

      container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

      var batch = new CompositionBatch();

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

      ...



      Now, I show the first ViewModel using:



      protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();


      All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.



      An example of a ViewModel is:




      [PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
      sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>

      [ImportingConstructor]
      public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)




      ...




      So far so good.



      Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?



      Here is what I am doing now. I am using ExportFactory of MEF. I have a class that holds a collection of ExportFactory, one for each IScreen.



      [Export(typeof(IScreenFactory))]
      class ScreenFactory : IScreenFactory

      private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary get; set;
      private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection get; set;
      private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx get; set;

      [ImportingConstructor]
      public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)

      _screenfactoryCollection = screenList;
      _reportfactoryCollection = reportsList;


      public IScreen GetScreen(Type t)

      if (_screenDictionary == null)

      PopulateScreenDictionary(_screenfactoryCollection);


      _currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
      return _currentScreenLifeTimeCtx.Value;


      private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)

      _screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);


      public void DisposeCurrentScreenContext()

      _currentScreenLifeTimeCtx?.Dispose();


      public void Dispose()

      DisposeCurrentScreenContext();




      Whenever I need a new instance of a ViewModel, I just publish a message using the EventAggregator and the MainViewModel does this:



      DeactivateItem(ActiveItem, true);
      _vmFactory.DisposeCurrentScreenContext();
      ActivateItem(_vmFactory.GetScreen(NextViewModelName));


      This CANNOT be the normal way to do so. Also, this adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30. That is because of how ExportFactory is messily implemented in the ScreenFactory class.



      I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.









      share|improve this question












      share|improve this question




      share|improve this question








      edited Jun 25 at 4:48









      Jamal♦

      30.1k11114225




      30.1k11114225









      asked Jun 20 at 18:15









      Mycroft Holmes

      112




      112

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f196911%2fswitching-between-viewmodels-using-ioc-in-a-mvvm-wpf-application%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f196911%2fswitching-between-viewmodels-using-ioc-in-a-mvvm-wpf-application%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation