Modern UI for WPF application by example ( NavigationService - MVVM )
Scope
This article has the goal to show how to create a navigation service for WPF application that uses Modern UI.
Introduction
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 find in mui.codeplex.com, here is possible to get the WPF app that demostrate the features provided by "mui".
WPF doesn´t have a pattern for navigation of Windows, the navigation service only works for Pages and UserControls. ModernUI introduces a special way for navigation - using 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 any implementation of INavigationService for WPF, to read see 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 to create the interface IModernNavigationService and the NavigationService, after it we will configure the navigation in MainWindow and then will use the navigation service in the view model for navigate to another view.
The interface will be something like
public interface IModernNavigationService : INavigationService
{
/// <summary>
/// Gets the parameter.
/// </summary>
/// <value>
/// The parameter.
/// </value>
object Parameter { get; }
}
which implementation will be
public class NavigationService : IModernNavigationService
{
private readonly Dictionary<string, Uri> _pagesByKey;
private readonly List<string> _historic;
/// <summary>
/// Initializes a new instance of the <see cref="NavigationService"/> class.
/// </summary>
public NavigationService()
{
_pagesByKey = new Dictionary<string, Uri>();
_historic = new List<string>();
}
/// <summary>
/// Gets the key corresponding to the currently displayed page.
/// </summary>
/// <value>
/// The current page key.
/// </value>
public string CurrentPageKey
{
get;
private set;
}
/// <summary>
/// Gets the parameter.
/// </summary>
/// <value>
/// The parameter.
/// </value>
public object Parameter { get; private set; }
/// <summary>
/// The go back.
/// </summary>
public void GoBack()
{
if (_historic.Count > 1)
{
_historic.RemoveAt(_historic.Count - 1);
NavigateTo(_historic.Last(), null);
}
}
/// <summary>
/// The navigate to.
/// </summary>
/// <param name="pageKey">
/// The page key.
/// </param>
public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}
/// <summary>
/// The navigate to.
/// </summary>
/// <param name="pageKey">
/// The page key.
/// </param>
/// <param name="parameter">
/// The parameter.
/// </param>
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;
// Set the frame source, which initiates navigation
if (frame != null)
{
frame.Source = _pagesByKey[pageKey];
}
Parameter = parameter;
_historic.Add(pageKey);
CurrentPageKey = pageKey;
}
}
/// <summary>
/// Configures the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="pageType">Type of the page.</param>
public void Configure(string key, Uri pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(key))
{
_pagesByKey[key] = pageType;
}
else
{
_pagesByKey.Add(key, pageType);
}
}
}
/// <summary>
/// Gets the name of the descendant from.
/// </summary>
/// <param name="parent">The parent.</param>
/// <param name="name">The name.</param>
/// <returns>The FrameworkElement.</returns>
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;
/// <summary>
/// Initializes a new instance of the <see cref="StepsViewModel"/> class.
/// </summary>
/// <param name="modernNavigationService">
/// The modern Navigation Service.
/// </param>
public StepsViewModel(IModernNavigationService modernNavigationService)
{
_modernNavigationService = modernNavigationService;
ResourcesCommand = new RelayCommand(ShowResources);
}
/// <summary>
/// Gets or sets the resources command.
/// </summary>
/// <value>The resources command.</value>
public ICommand ResourcesCommand { get; set; }
/// <summary>
/// Shows the resources.
/// </summary>
private void ShowResources()
{
_modernNavigationService.NavigateTo(ViewModelLocator.ResourcePageKey);
}
}
Note:
1. For send a parameter when navigate we should do
_modernNavigationService.NavigateTo(ViewModelLocator.ResourcePageKey, myParameterValue);
and then in the view model use the Parameter property, from the navigation service, for get the parameter
_modernNavigationService.Parameter
2. For navigate to the preview page use the GoBack method
_modernNavigationService.GoBack();
See others solutions for Navigation in ModernUI applications.
Modern UI for WPF application by example (handle navigation)
Modern UI for WPF application by example ( NavigationMessageService - MVVM )
Source code
Get the source code for this sample in github.