Best practice MVVM navigation using Master Detail page? -
i want follow mvvm pattern as possible, don't know if doing navigation quite well. note using masterdetail page , want maintain master page, changing detail side when navigate.
here way navigate viewmodel. in example, viewmodelone viewmodeltwo:
public class viewmodelone : viewmodelbase { private void gotoviewtwo() { var viewtwo = new viewtwo(new viewmodeltwo()); ((masterview)application.current.mainpage).navigatetopage(viewtwo); } }
masterview implementation:
public class masterview : masterdetailpage { public void navigatetopage(page page) { detail = new navigationpage(page); ispresented = false; } }
viewtwo implementation:
public partial class viewtwo : pagebase { public menuview(viewmodeltwo vm) : base(vm) { initializecomponent(); } }
pagebase implementation:
public class pagebase : contentpage { public pagebase(viewmodelbase vmb) { this.bindingcontext = vmb; } }
is best approach (and best performance) navigation? when navigations, app starts run slower , maybe there not doing fine.
is best approach navigation showing masterdetail page?
thanks.
i think you're on right track, there few issues here:
firstly, should not instantiating views in view model. view model becomes aware of view, you've pretty broken pattern.
var viewtwo = new viewtwo(new viewmodeltwo());
your view creation should responsibility of master view. in fact, don't need worry creating views, can use datatemplate
that. i'll explain later.
firstly, need separate view models views, here propose:
you'll need kind of base class
or interface
view models in order keep things generic, you'll see why in moment. let's start out simple example:
public abstract class viewmodel : inotifypropertychanged { public event eventhandler onclosed; public event eventhandler onopened; //don't forget implement inotifypropertychanged. public bool isdisplayed { get; private set; } public void open() { isdisplayed = true; //todo: raise onopened event (might better idea put in isdisplayed getter. } public void close() { isdisplayed = false; //todo: raise onclosed event. } }
this of course simple base view model, can extend on later, main reason allow create master view model responsible displaying current page. here's simple example of master view model:
public class masterviewmodel : inotifypropertychanged { //don't forget implement inotifypropertychanged. public viewmodel currentpage { get; private set; } public masterviewmodel() { //this example of how set current page. //you might want use command instead. currentpage = new movieviewmodel(); } //todo: other master view model functionality, exiting application. }
please note inotifypropertychanged
better in kind of base class, instead of having re-implement same code on , over.
now masterviewmodel
pretty simple, holds current page, purpose of having master allow application level code executed, closing app, way you're keeping logic away other view models.
right, onto stuff.
your detail has relationship it's parent, therefore make sense responsibility of parent manage it. in case, master-detail view model this:
public class movieviewmodel : viewmodel { protected pickgenreviewmodel childviewmodel { get; private set; } public movieviewmodel() { childviewmodel = new pickgenreviewmodel(); //todo: perhaps subscribe closed event? } //just example important thing note //this method protected because it's movieviewmodel's //responsibility manage it's child view model. protected void pickagenre() { childviewmodel.open(); } //todo: other view model functionality. }
so, we've got kind of view model structure here, bet you're asking "what views?", well, that's datatemplate
comes in.
in wpf, it's possible assign view type
, example, can assign movieview
movieviewmodel
in xaml, this:
xmlns:views="clr-namespace:yournamespace.views" xmlns:viewmodels="clr-namespace:yournamespace.viewmodels" ... <datatemplate datatype="{x:type viewmodels:movieviewmodel}"> <views:movieview/> </datatemplate>
ok great!, master view display current page's view, need create contentpresenter
, , bind it's content
currentpage
. master view this:
<window ... xmlns:viewmodels="clr-namespace:yournamespace.viewmodels"> <window.datacontext> <viewmodels:masterviewmodel/> </window.datacontext> <grid> <contentpresenter content="{binding currentpage}"/> </grid>
to extend further, it's not masterview
needs contain contentpresenter
it's child, movieview
needs 1 it's child pickgenreviewmodel
. can use same method again:
<grid> <!-- main view code movie view --> ... <border visibility="{binding childviewmodel.isdisplayed, converter=..."> <contentpresenter content="{binding childviewmodel}"/> </border> </grid>
note: use boolean visibility converter determine whether display child content.
using method don't have worry instantiating views, datatemplate
, contentpresenter
handles you, need worry mapping view models appropriate view.
phew! lot take in.
the main points take away are:
- you shouldn't creating views in view models, remember, ui ui, data data.
- view model responsibilities lie whoever owns them, parent-child relationship, makes sense let parent manage child, opposed view model manager.
a final note there more 1 other ways of achieving this, mentioned, kind of view , view model manager responsible creating/removing views , view models.
Comments
Post a Comment