Wednesday, May 18, 2011

Silverlight Navigation With the MVVM Pattern

I recently had a query from a customer that was one of those ones that you think “Aha! That’s easy, you just do this”. Then you think a bit more about it and realise that if you want to do it properly it’s not quite as simple as you first thought.

This particular query related to how to use the navigation framework introduced in Silverlight 3 with the MVVM pattern. For those that don’t know the Model-View-ViewModel pattern is a common pattern often used to build Silverlight and WPF applications since it has strong support for databound UIs and provides good abstraction for unit testing and keeping your view logic separate from the view and the model.

Enter the Silverlight Navigation Framework
Handling the page style navigation that we’ve all become used to on the web can be a real pain in RIAs written using Silverlight, Flash or AJAX involving lots of tracking of page clicks using HTML bookmarks and some liberal use of JavaScript. Fortunately Silverlight 3 added a navigation framework to help with this.

This framework works by you adding a Frame element to your root XAML and then creating many Page derived classes. These classes can then navigate between each other by calling into a NavigationService instance that each page inherits from it’s base class.
The issue with MVVM is that page navigation is a view logic, that means that it should sit inside the ViewModel, however the NavigationService is only on the Page class which the ViewModel doesn’t have access to.

Solving this problem is simple, just pass the NavigationService instance to the ViewModel, job done! Well ok, that works if you hate unit testing. If you like unit testing though you may find you have problems then when it comes to testing your ViewModel as you won’t have a NavigationService instance to pass it.

Additionally since many pages are likely to want to do this I’d like to have a reusable approach that doesn’t take much code to reuse.

The Solution
The solution I came up with is one of a few different ways you could implement this but this works for me at the moment. Feel free to point out any glaring errors in my design though.
Wrapping the NavigationService
First I need to make the NavigationService mockable so I can use it in unit tests. To do this I created a new interface INavigationService that exposes the methods and properties of the NavigationService. This sample version only exposes Navigate() but you could easily expose more as needed.

public interface INavigationService
{
void Navigate(string url);
}

Not the most complex interface ever devised you’ll agree.
Next I created a class that implemented the interface and took a reference to a System.Windows.Navigation.NavigationService on it’s constructor.

public class NavigationService : INavigationService
{
private readonly System.Windows.Navigation.NavigationService _navigationService;
public NavigationService(System.Windows.Navigation.NavigationService navigationService)
{
_navigationService = navigationService;
}