9 Comments
  •   Posted in: 
  • UWP

Until we get the great frameworks like Caliburn.Micro up-to-date with WinRT, one possible solution for doing navigation when using MVVM pattern is to wrap the Frame-object. Here’s a simple implementation (which could be further enhanced by extracting an interface from it): 

public class NavigationService
    {
        readonly Frame frame;

        public NavigationService(Frame frame)
        {
            this.frame = frame;
        }

        public void GoBack()
        {
            frame.GoBack();
        }

        public void GoForward()
        {
            frame.GoForward();
        }

        public bool Navigate<T>(object parameter = null)
        {
            var type = typeof(T);

            return Navigate(type, parameter);
        }

        public bool Navigate(Type source, object parameter = null)
        {
            return frame.Navigate(source, parameter);
        }
    }

The NavigationService can be initialized by passing in the root frame, for example in the App.xaml.cs where the root frame is created: 

// Create a Frame to act navigation context and navigate to the first page
            var rootFrame = new Frame();
            App.NavigationService = new NavigationService(rootFrame);

            rootFrame.Navigate(typeof(BlankPage));

If you’re using some container to create your view models, the NavigationService-instance can be registered into it as a singleton. If you’re using a simple ViewModelLocator without a container, the NavigationService can be added as a property to the App-class and it can be accessed when creating the view models. In either case, the NavigationService should be passed to the VM through the constructor, after which navigation from a view model is a straightforward task.

Here’s an example of a view model which uses the NavigationService to navigate forward to a new page:

public class BlankPageViewModel
    {
        private readonly NavigationService navigation;

        public BlankPageViewModel(NavigationService navigation)
        {
            this.navigation = navigation;
        }

        public DelegateCommand GoToNextPage
        {
            get
            {
                return new DelegateCommand(x => navigation.Navigate<SecondPage>(), x => true);
            }
        }
    }

The BlankPageViewModel is constructed inside the ViewModelLocator-class: 

public BlankPageViewModel BlankPageViewModel
        {
            get
            {
                return new BlankPageViewModel(App.NavigationService);
            }
        }

A sample app containing two pages and the NavigationService-wrapper can be found from GitHub. The sample app also shows a basic implementation of the view model locator.