[MVVMbasics] Handling navigation events

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

[important]Edited to reflect the changes in the MVVMbasics 2.1 release. The contents may not fully apply to older versions of the MVVMbasics framework.[/important]

One of the characteristics of an application developed with the help of the MVVMbasics framework is the tight coupling between Viewmodels and Views, that results in a 1 : 1 relation – for each View (each page in a Windows Phone or Windows Store App, or each window in a Desktop App), there exists exactly one related Viewmodel class. This allows the handling of basic navigation events as part of the Viewmodel logic, instead of handling those events in the View’s codebase as in traditional applications. This article summarizes the navigation events provided by the MVVMbasics Framework, and shows best-practice approaches of how to handle these events in order to detect basic life cycle information about your App. For more information about an App’s life cycle, read the article The Life Cycle of MVVMbasics Applications.

Prerequisites

Please note that navigation and navigation event handling works only if the following conditions apply:

  • All Views (pages / windows) in the App must subclass BaseView
  • All Viewmodel classes must subclass BaseViewmodel
  • The Application class itself must subclass BaseApplication
  • Views must provide an MvvmNavigationTarget attribute (when using one of the NavigatorService’s RegisterAll methods), or must be registered to the NavigatorService individually by calling the Register method
  • Each Viewmodel may be registered to only one View
  • Navigation must be accomplished only by using the NavigatorService’s NavigateTo and NavigateBack methods

Navigation Events

This section discusses the basic navigation handling methods provided by the BaseViewmodel class. If one of the basic life cycle events (see The Life Cycle of MVVMbasics Applications for details) of a View occurs, the according method in the attached Viewmodel is automatically called. To handle one of these methods, developers need to override the appropriate method in the Viewmodel class.

Some of these methods can be used to retrieve parameters that have been passed between Views. These parameters are passed as object of type ParameterList. Please refer to the Class Reference for detailed information about how to interact with ParameterList objects. For example, to retrieve a certain parameter value, use one of the GetX methods (e.g., GetString, GetInt, GetObject, etc.). To check whether the parameter collection contains a certain parameter value, use either the Contains method or one of the TryGetX methods (e.g., TryGetString, TryGetInt, TryGetObject, etc.)

OnNavigatedTo

The OnNavigatedTo method is called each time the according View comes into foreground – either because it is loaded for the first time, or because the App is re-activated from background or hibernation mode, or because another view that was hiding the current one is closed. If the View is newly loaded, the OnNavigatedTo method is called after the Constructor and the OnServiceLocatorAvailable method.

The OnNavigatedTo method has the following parameters:

  • uriParameters
    If the View was called from a URI (on the Windows Phone or Windows Store Platform), and the URI contained parameters, these are automatically parsed and passed to the OnNavigatedTo method as ParameterList object. In practice, parameters between Views should be passed as Parameter objects – these can be accessed through the parameters field explained below. The only common use case of the uriParameters field is startup through Secondary Tiles: When creating a Secondary Tile, you must specify the URI of the View to be opened on tapping this tile – this URI may contain parameters which may be referenced after App startup through the uriParameters field. On the Desktop platform, this field will always be empty.
    If one of these parameters shall be available throughout the execution of the App, it must be stored within a property, since the uriParameters field is emptied at the end of the OnNavigatedTo method, in contrast to the PhoneApplicationPage’s OnNavigatedTo method on the Windows Phone Platform!
  • parameters
    When navigating from one View to another (using the NavigatorService’s NavigateTo method), parameters to be passed on to the second View may be specified. In the second View’s attached Viewmodel, these can be retrieved through the OnNavigatedTo method’s parameters field.
    If one of these parameters shall be available throughout the execution of the App, it must be stored within a property, since the parameters field is emptied at the end of the OnNavigatedTo method.
  • viewState
    This field contains information about the attached View’s current state. This is automatically stored in the Viewmodel’s public ViewState property to be available any time throughout App execution. It may contain the following values:

    • Activated: The View is newly loaded, either because it has never been shown on the screen, or because it was closed and is now opened again.
    • Reactivated: The View has been inactive (e.g., another View had been opened that hides this one) and is reactivated (e.g., the hiding View is closed). On the Windows Phone and Windows Store platforms, opening a second page completely hides the current one. On the Desktop platform, opening a second Window might not completely hide the current one, but the current View loses focus – also in this case the OnNavigatedTo method is called with a ViewState of value Reactivated.
    • Shown: The whole App returns from an inactive state (e.g., because another App has moved to the background, and the current App comes into view again, or because the App has been minimized to the taskbar on the Desktop platform and is now restored), and the attached View is the one that is shown to the user (because it was the active view when the App was moved to the background).
    • Awakened: The whole App returns from suspended state, and the attached View is the one that is shown to the user (because it was the active view when the App entered hibernating mode). This ViewState occurs only on the Windows Phone Silverlight and WinRT platforms.

A usual approach to override the OnNavigatedTo method is to first check the ViewState and retrieve and process parameters based on it, as the following code snippet shows:

private override void OnNavigatedTo(ParameterList uriParameters, ParameterList parameters, ViewState viewState)
{
	switch (viewState)
	{
	case ViewState.Activated:
		// if the App was started from a Live Tile, check for URI parameters:
		// (in this case, let's assume that the ID of the object represented by the tile is provided as parameter)
		if (uriParameters.Contains("id")
		{
			int id = uriParameters.GetInt("id");
			// do something with the ID...
		}
		// check for View parameters:
		// (in this case, let's assume that a list of string values should be passed to this View)
		List<string> list;
		bool listAvailable = parameters.TryGetObject("list", out list);
		if (listAvailable)
		{
			foreach (string item in list)
			{
				// do something with the list items
			}
		}
		break;
	case ViewState.Reactivated:
		// check for parameters passed back from any closing View:
		if (parameters.Contains("backParameter"))
		{
			string backParameter = parameters.GetString("backParameter");
			// do something with the backParameter variable
		}
		break;
	case ViewState.Shown:
		// ensure that all of the View's contents are visible, if some contents have been hidden when
		// entering Hidden state
		break;
	case ViewState.Awakened:
		// optionally retrieve data written to IsoStorage on hibernation
		break;
	}
	// don't forget the following line:
	base.OnNavigatedTo(uriParameters, parameters, viewState);
}

CancelNavigatingFrom

The CancelNavigatingFrom method is called when the attached View is about to be closed in order to return back to the previously shown View (or to close the App if the attached View is the App’s main View). Override this method to accomplish one of the following things:

  1. to finish some work before the View is closed, e.g. passing parameters back to the previously shown View, or
  2. to cancel the navigation operation and force the App to stay on the current View

If only the first one applies, make sure to call return base.CancelNavigatingFrom(viewState); at the end of the method. If canceling the navigation, return true instead.

This method has only one parameter: The viewState field contains the state the current View is about to reach if the navigation will be performed. It may contain the following values:

  • Deactivated: Another View is loaded which will hide the current one. The current View is not closed but remains in the background.
  • Closed: The View is closed – if it shall be shown again at a later time, it must be instantiated again. The previously shown View will be re-activated. If the current View is the App’s main View, the App will be closed.
    This ViewState occurs when calling the NavigatorService’s NavigateBack method, or when the user presses the hardware back buttons on a Windows Phone device or clicks the [x] button to close the current window on the Desktop platform.

The following code sample shows a best-practice implementation of the CancelNavigatingFrom method:

private override void CancelNavigatingFrom(ViewState viewState)
{
	switch (viewState)
	{
	case ViewState.Deactivated:
		// let's assume that some text value must be filled in by the user before the next page may be opened
		// (if not, a message box is shown)
		if (String.IsNullOrEmpty(InputValue))
		{
			ServiceLocator.Retrieve<IMessageboxService>.Show("Please fill in the form!");
			return true;
		}
		break;
	case ViewState.Closed:
		// pass some parameter to the previously shown View:
		ServiceLocator.Retrieve<INavigatorService>.SetBackParameters(new Parameter("backParameter", SomePropertyValue));
		break;
	}
	// don't forget the following line:
	return base.CancelNavigatingFrom(viewState);
}

OnNavigatedFrom

The OnNavigatedFrom method is called after a navigation event to inform a Viewmodel instance that the View it is attached to has just been closed or deactivated. In practice, its main purpose is to save important data when the App is sent to hibernation mode. It has one parameter (viewState) that contains the state the current View has reached. It may contain the following values:

  • Deactivated: Another View has been loaded which hides this one. The View attached to this Viewmodel has not been closed but remains in the background.
  • Closed: The View has been closed – if it shall be shown again at a later time, it must be instantiated again. The previously shown View has been re-activated. If the current View is the App’s main View, the App is closed.
    This ViewState occurs when calling the NavigatorService’s NavigateBack method, or when the user presses the hardware back buttons on a Windows Phone device or clicks the [x] button to close the current window on the Desktop platform.
  • Hidden: The whole App is moving out of view. This can, for example occur when another App or the start screen comes into view on the Windows Phone Silverlight and WinRT platforms, or when the user minimizes the current App to the taskbar on the Desktop platform.
    This ViewState can be used to pause or hide some complex visual computation, because the user cannot see the View anyway. Don’t forget to re-start all those paused elements when the OnNavigatedTo event with a ViewState of type Shown occurs!
  • Hibernated: The whole App is suspended. This may only occur on the Windows Phone Silverlight and WinRT platforms and is done automatically by the operating system as soon as it runs out of memory – this is when application data should be written to IsoStorage in order to be able to retrieve it when re-activating the App.
    This ViewState does never occur on the Desktop platform, since this platform does not allow automatic App hibernation.

Note: On the Windows Phone Silverlight platform, there is no way to distinguish between an App being deactivated or suspended. Therefore, on this platform the OnNavigatedFrom event with a ViewState of Hidden never occurs, instead always the ViewState Hibernated is used.