Scope
The purpose of this article is to show how to create a navigation service for a WPF application that uses the Modern UI.
Introduction
The Modern UI is a set of controls and styles converting our WPF application into a great looking Modern UI app. The Modern UI project can be found in mui.codeplex.com, where it is possible to get the WPF app that demostrates the features provided by the “mui”.
WPF doesn´t have a pattern for navigation when we are using Windows, only a navigation service exists for when we use Pages. ModernUI introduces a special way for the navigation, that uses the ModernFrame.
For the sample we will use MVVMLight Toolkit for help in the MVVM pattern implementation and we will use a new feature provided by this toolkit, the INavigationService interface.
Note: The MVVMLight Toolkit doesn´t have an implementation of INavigationService for WPF, to see more about it read this article Announcing MVVM Light V5 for Windows and Xamarin.
Description
The source code base that we will use in this sample, is similar to the sample used in the article Modern UI for WPF application by example (Default Window).
We will start creating the interfaces IModernNavigationService and NavigationService, then we will configure the navigation in the MainWindow and then wil use the navigation service in the view model to navigate to another view.
The interface will be something like:
- public interface IModernNavigationService : INavigationService
- {
-
-
-
-
-
-
- object Parameter { get; }
- }
The implementation will be:
- public class NavigationService : IModernNavigationService
- {
- private readonly Dictionary<string, Uri> _pagesByKey;
- private readonly List<string> _historic;
-
-
-
-
- public NavigationService()
- {
- _pagesByKey = new Dictionary<string, Uri>();
- _historic = new List<string>();
- }
-
-
-
-
-
-
-
- public string CurrentPageKey
- {
- get;
- private set;
- }
-
-
-
-
-
-
-
- public object Parameter { get; private set; }
-
-
-
-
- public void GoBack()
- {
- if (_historic.Count > 1)
- {
- _historic.RemoveAt(_historic.Count - 1);
- NavigateTo(_historic.Last(), null);
- }
- }
-
-
-
-
-
-
-
- public void NavigateTo(string pageKey)
- {
- NavigateTo(pageKey, null);
- }
-
-
-
-
-
-
-
-
-
-
- public virtual void NavigateTo(string pageKey, object parameter)
- {
- lock (_pagesByKey)
- {
- if (!_pagesByKey.ContainsKey(pageKey))
- {
- throw new ArgumentException(string.Format("No such page: {0}. Did you forget to call NavigationService.Configure?", pageKey), "pageKey");
- }
-
- var frame = GetDescendantFromName(Application.Current.MainWindow, "ContentFrame") as ModernFrame;
-
-
- if (frame != null)
- {
- frame.Source = _pagesByKey[pageKey];
- }
- Parameter = parameter;
- _historic.Add(pageKey);
- CurrentPageKey = pageKey;
- }
- }
-
-
-
-
-
-
- public void Configure(string key, Uri pageType)
- {
- lock (_pagesByKey)
- {
- if (_pagesByKey.ContainsKey(key))
- {
- _pagesByKey[key] = pageType;
- }
- else
- {
- _pagesByKey.Add(key, pageType);
- }
- }
- }
-
-
-
-
-
-
-
- private static FrameworkElement GetDescendantFromName(DependencyObject parent, string name)
- {
- var count = VisualTreeHelper.GetChildrenCount(parent);
-
- if (count < 1)
- {
- return null;
- }
-
- for (var i = 0; i < count; i++)
- {
- var frameworkElement = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
- if (frameworkElement != null)
- {
- if (frameworkElement.Name == name)
- {
- return frameworkElement;
- }
-
- frameworkElement = GetDescendantFromName(frameworkElement, name);
- if (frameworkElement != null)
- {
- return frameworkElement;
- }
- }
- }
-
- return null;
- }
- }
And the setup for the navigation will be done in the MainWindow.xaml.cs, something like:
- private void SetupNavigation()
- {
- var navigationService = new NavigationService();
- navigationService.Configure(ViewModelLocator.ResourcePageKey, new Uri("Views/ResourcesView.xaml"));
- navigationService.Configure(ViewModelLocator.StepsPageKey, new Uri("Views/StepsView.xaml"));
-
- SimpleIoc.Default.Register<IModernNavigationService>(() => navigationService);
- }
In the StepsViewModel we will do:
- public class StepsViewModel : ViewModelBase
- {
- private readonly IModernNavigationService _modernNavigationService;
-
-
-
-
-
-
-
- public StepsViewModel(IModernNavigationService modernNavigationService)
- {
- _modernNavigationService = modernNavigationService;
- ResourcesCommand = new RelayCommand(ShowResources);
- }
-
-
-
-
-
- public ICommand ResourcesCommand { get; set; }
-
-
-
-
- private void ShowResources()
- {
- _modernNavigationService.NavigateTo(ViewModelLocator.ResourcePageKey);
- }
- }
Note:
- To send a parameter when we navigate we should do:
- modernNavigationService.NavigateTo(ViewModelLocator.ResourcePageKey, myParameterValue);
And then in the view model use the Parameter property, from the navigation service, to get the parameter.
- _modernNavigationService.Parameter;
- To navigate to the preview page use the GoBack method:
- _modernNavigationService.GoBack();
Source Code
Get the source code for this sample in
github.
<< Modern UI for WPF application by example (Handle Navigation: (Default)) Part-1