Recently, I 've been reading the deep dive mvvm of Laurent Bugnion. I 've learned a lot about it. This article only focuses on how to initiate page navigation from viewmodel.
The demo in this article is also very simple. masterpage loads some information using ListBox, click any of the items, navigate to detailspage and display the details of the selected items, as shown in.
Set masterpageto masterviewmodel, and detailspageto detailsviewmodel. the code is in mvvmnavigationdemo.zip. The following describes only key technical points.
1. Declare the inavigationservice interface and implement an inherited navigationservice class.
Public interface inavigationservice
{
Event navigatingcanceleventhandler navigating;
Void navigateto (URI );
Void Goback ();
}
Public class navigationservice: inavigationservice
{
Private phoneapplicationframe _ mainframe;
Public Event System. Windows. Navigation. navigatingcanceleventhandler navigating;
Public void navigateto (URI)
{
If (ensuremainframe ())
{
_ Mainframe. navigate (URI );
}
}
Public void Goback ()
{
If (ensuremainframe () & _ mainframe. cangoback)
{
_ Mainframe. Goback ();
}
}
Private bool ensuremainframe ()
{
If (_ mainframe! = NULL)
{
Return true;
}
_ Mainframe = application. Current. rootvisual as phoneapplicationframe;
If (_ mainframe! = NULL)
{
_ Mainframe. Navigating + = (S, e) =>
{
If (navigating! = NULL)
{
Navigating (S, e );
}
};
}
Return false;
}
}
2. Declare the inavigationservice field and selecteditem attribute in the masterviewmodel class.
Public class masterviewmodel: viewmodelbase
{
Public inavigationservice navigationservice {Get; set ;}
Public observablecollection <Friendviewmodel> Friends
{
Get;
Private set;
}
Public const string selectedfriendpropertyname = "selecteditem ";
Private friendviewmodel _ selecteditem = NULL;
Public friendviewmodelSelecteditem
{
Get {return _ selecteditem ;}
Set
{
If (_ selecteditem = value)
Return;
VaR oldvalue = _ selecteditem;
_ Selecteditem = value;
Raisepropertychanged (selectedfriendpropertyname, oldvalue, _ selecteditem, true );
If (navigationservice! = NULL)
{
// Call the navigationservice instance method to navigate to the page
Navigationservice. navigateto (viewmodellocator. detailspageuri );
}
}
}
}
Note: In this change notification, the viewmodelbase overload method is used to initiate the propertychanged event and broadcast a propertychangedmessage. Another important skill in this article is to use the inavigationservice interface to call the navigation method.
3. Add the selecteditem attribute to the detailsviewmodel, register and accept the propertychangedmessage message in the default structure, and execute the passed action when receiving the message.
Public partial class detailsviewmodel: viewmodelbase
{
Public const string selectedfriendpropertyname = "selecteditem ";
Private friendviewmodel _ selecteditem = NULL;
Public friendviewmodelSelecteditem
{
Get
{
Return _ selecteditem;
}
Set
{
If (_ selecteditem = value)
{
Return;
}
_ Selecteditem = value;
Raisepropertychanged (selectedfriendpropertyname );
}
}
Public detailsviewmodel (ifriendsservice friendsservice)
{
......
Messenger. Default. register <propertychangedmessage <friendviewmodel> (
This,
Message =>
{
Selecteditem = NULL;
Selecteditem = message. newvalue;
});
......
}
4. Register masterviewmodel/detailsviewmodel with simpleioc and add the master/detail attribute to viewmodellocator. At the same time, assign the navigationservice field of the master to the instance of navigationservice.
Public class viewmodellocator
{
Public static readonly URI detailspageuri = new uri ("/detailspage. XAML", urikind. Relative );
Static viewmodellocator ()
{
Servicelocator. setlocatorprovider () => simpleioc. Default );
If (viewmodelbase. isindesignmodestatic)
{
Simpleioc. Default. register <ifriendsservice, design. designfriendsservice> ();
}
Else
{
Simpleioc. Default. register <ifriendsservice, friendsservice> ();
}
Simpleioc. Default. register <masterviewmodel> ();
// Ensure VM
VaR master = simpleioc. Default. getinstance <masterviewmodel> ();
Simpleioc. Default. register <detailsviewmodel> ();
// Ensure VM
Simpleioc. Default. getinstance <detailsviewmodel> ();
Master. navigationservice = new navigationservice ();
}
/// <Summary>
/// Gets the main property.
/// </Summary>
[System. Diagnostics. codeanalysis. suppressmessage ("Microsoft. Performance ",
"Ca1822: markmembersasstatic ",
Justification = "this non-static member is needed for Data Binding purposes.")]
Public masterviewmodelMaster
{
Get
{
Return servicelocator. Current. getinstance <masterviewmodel> ();
}
}
Public detailsviewmodelDetails
{
Get
{
Return simpleioc. Default. getinstance <detailsviewmodel> ();
}
}
}
Demo source code: mvvmnavigationdemo.zip