Navigate in code

Jul 2, 2010 at 11:58 PM
Edited Jul 3, 2010 at 12:00 AM

Couple of questions.  I had a need to navigate in code and here is what I was doing which seems to work:

    var request = new NavigationRequest(Url); 
           NavigationService.Navigate(request);


Is this the best way to do this? I need to do this inside of a command and it wasn't apparent how to have a command end up performing a navigation.  I understand this may not be the right way to do it, but it did come up.
My next question is can you have a navigationcontainer call a controller action instead of a normal site map node?  I was thinking it would be good to have my main container call a controller method like "Start" and depending on what was going on in the app I could give it different navigationresults.   For now I have my Shell controller perform the logic and bind my browsing container to that viewmodel.
Thanks a lot.

 

Coordinator
Jul 3, 2010 at 2:55 PM

First thing, yes the code bit you wrote is correct but incomplete - the reason being that you need to tell which container to navigate. Now, the Navigate method overload that you are using (the one which doesn't require the container specified) assumes that you have an "application-wide" default container specified. If you don't then it will raise an error. To specify any container as the application-wide default container use the "NavigationHandler" behavior and set "IsDefaultHandler" to be true. You can also do this programatically by setting the DefaultNavigationHandler property on NavigationService static class.

Couple of points about navigating:

  • Normally the best to navigate is to use the "NavigationAction" behavior - as you can use it will all sorts of triggers.
  • Also, I'm not sure if you want to navigate using Code in your ViewModel, but I personally would not recommend it - the reason being that the "specifics" of how to change the View should remain in your View world. Or more broadly speaking, the VM is your logical model, and View is its visual realization. And so VM should essentially say the View should change, but now how - that's upto the View specifics. This way your VM is not specific to a navigation-based model..
  • And if you wondering how can a VM "logically" ask the View to change, and then in turn View navigates? Use something called ReverseCommand in nRoute (see http://www.orktane.com/Blog/post/2010/01/07/Reverse-ICommands-for-MVVM.aspx) - that's how I do it.
  • If you get my gist above, then really you shouldn't navigate using a command - also if you use the NavigationAction behavior then you don't need to really. Because let's say with a button, you can drag-drop the NavigateAction behavior and then specify trigger for it. The trigger-action pairing can readily replace any command type contraption, that being said, technically you can still do it in a command. 

About the SiteMap/Controller thing, I'm not clear on your question. But, the basics are that

  • You can declare controller-based actions in your SiteMap, and (optionally) give them a key. 
  • If you have given it a key, you can directly execute the ControllerAction using a ExecuteControllerNodeAction behavior (and like with NavigateAction you can rig it with any sort of trigger) by specifying the key. 
  • On the other hand, when lets say you are binding the SiteMap nodes (doesn't matter if they Controller types of Navigation nodes) to ItemsControl then you can use the ExecuteSiteMapNodeAction. There is not much difference between them, just ExecuteControllerNodeAction is a specialization (much like NavigateNodeAction) over ExecuteSiteMapNodeAction. 

And if you were asking if you can bypass SiteMaps to directly execute a Controller Action - then absolutely. You basically declare your container, like say below:

 

[MapController("Tasks/Main/{Action}"]
public class ShellController : Controller
{
	public ActionResult Start()
	{
		if (x == y)
		{
			return new NavigateResult("Pages/Main/PageA/");
		} 
		else
		{
			return new NavigateResult("Pages/Main/PageB/");
		}
	}
}

And then quite like NavigateAction use the ExecuteControllerAction and specify the url - for the above it should be "Tasks/Main/Start/". And you can put anything in the start method's logic, that's upto you. The only thing to be careful about is above is which container will the NavigateResult target - the answer is unless you specify specifically using an overload, it will try to use the navigation container that triggered the action, if that is unknown then it will try use the application-wide container, all else it will raise an error.

Hope that helps..
Rishi