Here's my implementation of a navigation service. Not going to claim it's perfect, but it works for me. This also pre-dates the built-in navigation service in MVVM Light 5, but you may be able to still make use of it, or parts of it.
Register it in ViewModelLocator using
SimpleIoc.Default.Register<INavigationService, NavigationService>();
and then inject it into your view models via the constructor. Use NavigateTo()
to navigate to other pages; the back button pressed handler exits the application only when there is no more history, otherwise it navigates to the previous page.
public interface INavigationService
{
void NavigateTo(Type pageType, object parameter = null);
void NavigateTo(string pageName, object parameter = null);
void GoBack();
}
.
public class NavigationService : INavigationService
{
#region Public
/// <summary>
/// Navigates to a specified page.
/// </summary>
public void NavigateTo(string pageName, object parameter = null)
{
Type pageType = Type.GetType(string.Format("SendToSync.{0}", pageName));
if (pageType == null)
throw new Exception(string.Format("Unknown page type '{0}'", pageName));
NavigateTo(pageType, parameter);
}
/// <summary>
/// Navigates to a specified page.
/// </summary>
public void NavigateTo(Type pageType, object parameter = null)
{
var content = Window.Current.Content;
var frame = content as Frame;
if (frame != null)
{
var previousPageType = frame.Content.GetType();
if (previousPageType != pageType)
NavigationHistory.Add(previousPageType);
//await frame.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => frame.Navigate(pageType));
frame.Navigate(pageType, parameter);
}
Window.Current.Activate();
}
/// <summary>
/// Goes back.
/// </summary>
public void GoBack()
{
var content = Window.Current.Content;
var frame = content as Frame;
if (frame != null)
{
var currentPageType = frame.Content.GetType();
// remove the previous page from the history
var previousPageType = NavigationHistory.Last();
NavigationHistory.Remove(previousPageType);
// navigate back
frame.Navigate(previousPageType, null);
}
}
#endregion
#region Private
/// <summary>
/// The navigation history.
/// </summary>
private List<Type> NavigationHistory { get; set; }
#endregion
#region Initialization
public NavigationService()
{
NavigationHistory = new List<Type>();
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
/// <summary>
/// Called when the back button is pressed; either navigates to the previous page or exits the application.
/// </summary>
private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
if (NavigationHistory.Count == 0)
{
e.Handled = false;
}
else
{
e.Handled = true;
GoBack();
}
}
#endregion
}
EDIT: Here's parts of my ViewModelLocator
In the constructor:
SimpleIoc.Default.Register<MainViewModel>();
And the accompanying property:
public MainViewModel MainViewModel
{
get { return ServiceLocator.Current.GetInstance<MainViewModel>(); }
}
This will always return the same single instance of MainViewModel
(and the view model data will persist).