maandag 16 mei 2011

MVVM navigation between pages in Silverlight

I see allot of question on the internet asking how we can perform navigation in MVVM for Silverlight.  There are allot of answers but most of them involve some coupling between the View and ViewModel.  The following answer I will provide will guarantee the following:
  • Completely loose coupled
  • View is responsible for calling another view
  • No need for knowing the URI of each page
So what is the basic setup.  Since a picture is worth more than a thousand words, I made on for you with my expert paint skills:


As you can see I’ve made both a base ViewModel as a Base View.  Both of them encapsulate the requests and handling of the request for navigating to another View.  The request is executed by using the MVVMlight Messenger class.  Enough gibberish here is the code of the 2 base classes:


    public class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase
    {
        public static string RequestedViewName { get; private set; }

        public static void NavigateToView(string viewName)
        {
            RequestedViewName = viewName;
            Messenger.Default.Send<string>(viewName, "NavigationRequest");
        }
    }

    public partial class NavigationPage : Page
    {
        public NavigationPage()
        {

        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            Messenger.Default.Unregister<string>(this);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Listen for navigation requests and redirect to the requested page
            Messenger.Default.Register<string>(this, "NavigationRequest", (viewName) => ViewManager.Navigate(viewName, this));
        }
    }

The base ViewModel will send a request with the name of view in it.  The View will the capture the request and ask the ViewManager to handle the logic.  The main reason why we want to do this in the page is because we have easy access to the NavigationService.

Then the ViewManager will parse the view string and navigate to the corresponding Uri.  The Uri is determined by using a class I wrote a while back called the PageUriLocator:

    public class ViewManager
    {
        public static Uri GetUriFromViewName(string viewName)
        {
            string uri;
            switch (viewName)
            {
                case "About":
                    uri = PageUriLocator.GetUri<about>();
                    break;
                case "Home":
                    uri =PageUriLocator.GetUri<home>();
                    break;
                default:
                    throw new ArgumentException("Page does not exist");
            }
            return new Uri(uri, UriKind.RelativeOrAbsolute);
        }

        public static void Navigate(string viewName, NavigationPage page)
        {
            Uri uri = GetUriFromViewName(viewName);
            if (uri != null)
                page.NavigationService.Navigate(uri);
        }
    }

Then when we want to navigate in our ViewModel we can just do this:

    public class HomeViewModel: ViewModelBase
    {
        public RelayCommand NavigateToAbout
        {
            get
            {
                return new RelayCommand(() => NavigateToView("About"));
            }
        }
    }

I’ve included a sample here.
Have fun coding ;)

1 opmerking:

  1. Thomas Magle Brodersen24 oktober 2013 om 10:05

    Very nice! Is that sample still available? The link does not work...

    BeantwoordenVerwijderen