NavigationService for WinRT

4 minute read

"If I have been able to see further than others, it is because I have stood on the shoulders of giants."
 Isaac Newton

It was only 1.5 years ago, but it seems already a long time ago that Laurent Bugnion described a “view service” for Windows Phone navigation, commonly know as the NavigationService. I’ve incorporated this code in my #wp7nl library on codeplex and have been using it happily ever since (and a lot of other people I know have been doing so as well), Time goes on, along came Windows 8 and WinRT and Metro Style Apps.

Laurent ported his MVVMLight framework to WinRT as well. But the NavigationService never has been a core part of MVVMLight (therefore I put it in the #wp7nl library) and porting it to WinRT as well proved to be a bit of a hassle. Some of its premises where no longer valid – most notable the way to retrieve the main application frame by accessing Application.Current.RootVisual, which does not work in WinRT. I messed around a little with the code, did not get anywhere, and left it there. So I was glad I saw my fellow Windows Phone Development MVP Matteo Pagani tweet he got a NavigationService to work. He was kind enough to mail me the code. He basically copied the code from Windows Phone and made the apps rootFrame, as created in the App.xaml.cs, publicly available. A neat trick, with as only drawback that you have to copy the code to every app. As things goes, it’s usually easier to see someone else’s idea and improve it, than think it up out of the blue. I toyed around with it and managed to get rid of the need to copy the code, so I could put it in a library.

And here it is, an improved version of a NavigationService for WinRT, based upon Matteo’s code based upon Laurent’s code ;-)

First of all, the NavigationService’s interface:

using System;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public interface INavigationService
  {
    event NavigatingCancelEventHandler Navigating;
    void Navigate(Type type);
    void Navigate(Type type, object parameter);
    void Navigate(string type);
    void Navigate(string type, object parameter);
    void GoBack();
  }
}

This quite looks like the old interface, with some notable exceptions. First of all, the NavigateTo method is renamed Navigate, to mimic the method name used in WinRT itself. And it has not one but four overloads. The first two are pretty logical – WinRT does not use an uri for navigation, but an actual Type object, making strongly-typed navigation possible. And it supports an overload for a parameter object, as well. The two other methods, with the string type object… well see for yourself below, in the implementation of the service:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Win8nl.Services
{
  public class NavigationService : INavigationService
  {
  public NavigationService(Frame mainFrame)
  {
    _mainFrame = mainFrame;
  }

  private Frame _mainFrame;
  
  public event NavigatingCancelEventHandler Navigating;

  public void Navigate(Type type)
  {
    _mainFrame.Navigate(type);
  }

  public void Navigate(Type type, object parameter)
  {
    _mainFrame.Navigate(type, parameter);
  }

  public void Navigate(string type, object parameter)
  {
    _mainFrame.Navigate(Type.GetType(type), parameter);
  }

  public void Navigate(string type)
  {
    _mainFrame.Navigate(Type.GetType(type));
  }

  public void GoBack()
  {
    if (_mainFrame.CanGoBack)
    {
      _mainFrame.GoBack();
    }
  }  
}

So the string type methods allow you to specify the page to navigate by string. Before you all think I really lost my marbles this time, re-introducing weakly typed navigation just as the Windows team introduced strongly typed: I specifically added this as to allow navigation to be initiated from a ViewModel contained in an assembly not containing the XAML code. This also enables you to test code as well. This is the way I built my solutions for Windows Phone, and I intend to go on this way in Windows 8. ;-)

Anyway, there’s a thing missing in this code: the EnsureMainFrame that looked up the root page, for which Matteo used a public property. I completely removed it, and added a constructor accepting that root page. By creating that constructor I deleted the default constructor, so registering the NavigationService at he SimpleIoc container shipped with MVVMLight in the App.xaml.cs, like this:

SimpleIoc.Default.Register<INavigationService, Wp7nl.Utilities.NavigationService>();

as we did in Windows Phone code, won’t work anymore. Fortunately, SimpleIoc also supports factory methods to create an instance. So now you go to the App.xaml.cs of your Windows 8 app, find the OnLaunched method and just behind this line:

var rootFrame = new Frame();

you add this piece of code:

SimpleIoc.Default.Register<INavigationService>(() => 
                                   {return new NavigationService(rootFrame);});

Now if your XAML code and ViewModels are all in one assembly, you can call the NavigationService to navigate to the main page this:

SimpleIoc.Default.GetInstance<INavigationService>().Navigate(typeof(MainPage));

or if you are a bit stubborn like me and would like to separate ViewModels and views, you can use the string overload to specify the full qualified name and for instance use it in a ViewModel command like this

public ICommand TestNavigatieCommand
{
   get
   {
     return new RelayCommand(() => 
       SimpleIoc.Default.GetInstance<INavigationService>().Navigate("MyApp.MainPage,MyApp"));
   }
}

And there you have, a fully functional NavigationService for Windows 8. Code can be downloaded here. I will soon incorporate it in the provisional port of the #wp7nl library called win8nl.

Thanks to Laurent and Matteo for being my trailblazers ;-)