c# - Better way to handle navigation between ContentControls in WPF MVVM? -


i developing c# wpf application , trying follow mvvm design pattern.

the way working now, using contentcontrol in main window , binding currentviewmodel, , declaring in app.xaml datatemplates. when want change current view in main window, have change currentviewmodel property in main window's view model, works well. also, in order not have direct reference of view model (by doing new blablaviewmodel() in view model), have singleton flowmanager class call in icommand function, , instantiation done in class rather view model.

the problem approach, each view add application, have add datatemplate in app.xaml, enum entry in flowmanager class , new case in switch() in changepage() function, new icommand in mainviewmodel, on top of adding code actual view , creating it's own view model.

here example of how handle flow of application:

in mainwindow.xaml, have following layout:

<window x:class="eveexcelmineralupdater.views.mainwindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:viewmodels="clr-namespace:eveexcelmineralupdater.viewmodels"         title="mainwindow" height="720" width="1280">     <grid>         <grid.columndefinitions>             <columndefinition width="15*"/>             <columndefinition width="auto"/>             <columndefinition width="85*"/>         </grid.columndefinitions>          <stackpanel grid.column="0">             <button>marketstat request</button>             <button command="{binding changetoquicklookcommand}">quicklook request</button>             <button>history request</button>             <button>route request</button>             <button>settings</button>         </stackpanel>          <separator grid.column="1" style="{staticresource {x:static toolbar.separatorstylekey}}" />          <contentcontrol grid.column="2" content="{binding currentviewmodel}" />     </grid> </window> 

in app.xaml.cs start application creating main window , settings datacontext , mainviewmodel property:

mainwindow mainwindow = new mainwindow(); mainviewmodel mainviewmodel = new mainviewmodel(); mainwindow.datacontext = mainviewmodel; mainwindow.viewmodel = mainviewmodel;  flowmanager.instance.appwindow = mainwindow;  mainwindow.show(); 

in mainviewmodel.cs, handle button request change currentview property icommand follows:

private void changetoquicklook(object param) {     flowmanager.instance.changepage(flowmanager.pages.quicklook); } ... public icommand changetoquicklookcommand {     { return new relaycommand(changetoquicklook); } } 

in flowmanager.cs, have enum lists pages (views) in application, , actual changepage() function change currentviewmodel property in mainviewmodel:

// 1 view implemented now, rest empty public void changepage(pages page) {     iviewmodel newviewmodel = null;      switch (page)     {         case pages.marketstat:             break;         case pages.quicklook:             newviewmodel = new quicklookrequestviewmodel();             break;         case pages.history:             break;         case pages.route:             break;         case pages.settings:             break;     }      appwindow.viewmodel.currentviewmodel = newviewmodel; } ... public enum pages {     marketstat,     quicklook,     history,     route,     settings } 

finally, in app.xaml, have list of datatemplates views:

<application x:class="eveexcelmineralupdater.app"              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"              xmlns:viewmodels="clr-namespace:eveexcelmineralupdater.viewmodels"              xmlns:views="clr-namespace:eveexcelmineralupdater.views"              startup="app_onstartup">     <application.resources>         <!-- pages datatemplates -->         <datatemplate datatype="{x:type viewmodels:quicklookrequestviewmodel}">             <views:quicklookrequestview />         </datatemplate>     </application.resources> </application> 

like said, works well, can see scalability problems have modify several parts of code in order add view in application. there better way without use of frameworks?

after looking @ @wojciechkulik comment, have come following change in flowmanager.cs class:

public class flowmanager {     private static flowmanager _instance;      private mainwindow _mainwindow;     private icollection<iviewmodel> _viewmodels;       private flowmanager()     {         viewmodels = new list<iviewmodel>();     }      public void changepage<tviewmodel>() tviewmodel : iviewmodel, new()     {         // if on same page button click, don't change         if (appwindow.viewmodel.currentviewmodel == null ||              appwindow.viewmodel.currentviewmodel.gettype() != typeof(tviewmodel))         {             foreach (iviewmodel viewmodel in viewmodels)             {                 // if instance of viewmodel exists, switch 1                 if (viewmodel.gettype() == typeof(tviewmodel))                 {                     appwindow.viewmodel.currentviewmodel = viewmodel;                     return;                 }             }              // else, create new instance of viewmodel             tviewmodel newviewmodel = new tviewmodel();             appwindow.viewmodel.currentviewmodel = newviewmodel;             viewmodels.add(newviewmodel);         }     }      public static flowmanager instance     {                 {             if (_instance == null)             {                 _instance = new flowmanager();             }              return _instance;         }     }      public mainwindow appwindow { get; set; }      public icollection<iviewmodel> viewmodels { get; private set; } } 

this way, add support keeping state of each of view's viewmodel, , got rid of enum entry each view have in application using power of generics , reflection.

i update answer if find other ways reduce number of places have modify each view want add application.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -