Modern UI For WPF Application by Example (Handle Navigation: (Default)): Part 1

Scope

The purpose of this article is to show how to create a blank window in WPF using the Modern UI that handles the navigation.

Introduction

The Modern UI is a set of controls and styles that can make our WPF application into a great looking Modern UI app. The Modern UI project can be found in mui.codeplex.com. Here it is possible to get the WPF app that demostrates the features provided by the “mui”.

WPF doesn´t have a pattern for the navigation when we are using Windows, it only has a navigation service for when we use Pages. The ModernUI introduced a special way for the navigation, that uses the ModernFrame. The question here is, how do I know when the user is navigating from one view to another?

Description

In the sample Modern UI for WPF application by example (Default Window) we saw the default window provided by the Modern UI and in this sample we will use the same base code but we will change the code to handle the navigation.

If we search the properties from the ModernWindow, we will see that it doesn´t have any event or method to handle navigation. After some searching in the documentation, we found the article Handle navigation events in your content.

Let's apply it!

The MainWindow contains a MenuLinkGroups that contains a LinkGroup with two Links. Each link is defined by a UserControl. To handle the navigation, each user control will implement the interface IContent, like the following:

  1. /// <summary>  
  2. /// Interaction logic for StepsControl.xaml.  
  3. /// </summary>  
  4. public partial class StepsControl : IContent  
  5. {  
  6.     /// <summary>  
  7.     /// Initializes a new instance of the <see cref="StepsControl"/> class.  
  8.     /// </summary>  
  9.     public StepsControl()  
  10.     {  
  11.         InitializeComponent();  
  12.     }  
  13.    
  14.     /// <summary>  
  15.     /// Called when navigation to a content fragment begins.  
  16.     /// </summary>  
  17.     /// <param name="e">An object that contains the navigation data.</param>  
  18.     public void OnFragmentNavigation(FragmentNavigationEventArgs e)  
  19.     {  
  20.         Debug.WriteLine("StepsControl- OnFragmentNavigation");  
  21.     }  
  22.    
  23.     /// <summary>  
  24.     /// Called when this instance is no longer the active content in a frame.  
  25.     /// </summary>  
  26.     /// <param name="e">An object that contains the navigation data.</param>  
  27.     public void OnNavigatedFrom(NavigationEventArgs e)  
  28.     {  
  29.         Debug.WriteLine("StepsControl -OnNavigatedFrom");  
  30.     }  
  31.    
  32.     /// <summary>  
  33.     /// Called when a this instance becomes the active content in a frame.  
  34.     /// </summary>  
  35.     /// <param name="e">An object that contains the navigation data.</param>  
  36.     public void OnNavigatedTo(NavigationEventArgs e)  
  37.     {  
  38.         Debug.WriteLine("StepsControl- OnNavigatedTo");  
  39.     }  
  40.    
  41.     /// <summary>  
  42.     /// Called just before this instance is no longer the active content in a frame.  
  43.     /// </summary>  
  44.     /// <param name="e">  
  45.     /// An object that contains the navigation data.  
  46.     /// </param>  
  47.     /// <remarks>  
  48.     /// The method is also invoked when parent frames are about to navigate.  
  49.     /// </remarks>  
  50.     public void OnNavigatingFrom(NavigatingCancelEventArgs e)  
  51.     {  
  52.         Debug.WriteLine("StepsControl- OnNavigatingFrom");  
  53.     }  
  54. }  
Using Debug.WriteLine we will show in the Output window the flow when we navigate into the MainWindow.

The output will be something like:

StepsControl - OnNavigatedTo
StepsControl - OnNavigatingFrom
StepsControl - OnNavigatedFrom
ResourcesControl - OnNavigatedTo
ResourcesControl - OnNavigatingFrom
ResourcesControl - OnNavigatedFrom
StepsControl - OnNavigatedTo
StepsControl - OnNavigatingFrom
StepsControl - OnNavigatedFrom
ResourcesControl - OnNavigatedTo

See the code source in github – ModernUIForWPFSample.Navigation (Default).

Suppose that when we navigate we want to do some task and we are using the MVVM pattern. We could get the view model defined in DataContext and then call the relevant method, something like:
  1. public void OnNavigatedTo(NavigationEventArgs e)  
  2. {  
  3.     var viewModel = DataContext as MyViewModel;  
  4.     if (viewModel != null)  
  5.     {  
  6.         viewModel.DoSomething();  
  7.     }  
  8. }  
Or we can define events that will be called when the methods from IContent are raised and the events can be defined in the UI using the EventTrigger and InvokeCommandAction. With this we will avoid code in the code behind.

First we will create our ModernUserControl that is a UserControl and implement IContent. This control will have four events, one for each method required for IContent.

The implementation will be something like:
  1. public class ModernUserControl : UserControl, IContent  
  2. {  
  3.     /// <summary>  
  4.     /// Handles the <see cref="E:FragmentNavigation"/> event.  
  5.     /// </summary>  
  6.     /// <param name="e">The <see cref="FirstFloor.ModernUI.Windows.Navigation.FragmentNavigationEventArgs"/> instance containing the event data.</param>  
  7.     public void OnFragmentNavigation(FragmentNavigationEventArgs e)  
  8.     {  
  9.         if (FragmentNavigation != null)  
  10.         {  
  11.             FragmentNavigation(this, e);  
  12.         }  
  13.     }  
  14.    
  15.     /// <summary>  
  16.     /// Handles the <see cref="E:NavigatedFrom"/> event.  
  17.     /// </summary>  
  18.     /// <param name="e">The <see cref="FirstFloor.ModernUI.Windows.Navigation.NavigationEventArgs"/> instance containing the event data.</param>  
  19.     public void OnNavigatedFrom(NavigationEventArgs e)  
  20.     {  
  21.         if (NavigatedFrom != null)  
  22.         {  
  23.             NavigatedFrom(this, e);  
  24.         }  
  25.     }  
  26.    
  27.     /// <summary>  
  28.     /// Handles the <see cref="E:NavigatedTo"/> event.  
  29.     /// </summary>  
  30.     /// <param name="e">The <see cref="FirstFloor.ModernUI.Windows.Navigation.NavigationEventArgs"/> instance containing the event data.</param>  
  31.     public void OnNavigatedTo(NavigationEventArgs e)  
  32.     {  
  33.         if (NavigatedTo != null)  
  34.         {  
  35.             NavigatedTo(this, e);  
  36.         }  
  37.     }  
  38.    
  39.     /// <summary>  
  40.     /// Handles the <see cref="E:NavigatingFrom"/> event.  
  41.     /// </summary>  
  42.     /// <param name="e">The <see cref="FirstFloor.ModernUI.Windows.Navigation.NavigatingCancelEventArgs"/> instance containing the event data.</param>  
  43.     public void OnNavigatingFrom(NavigatingCancelEventArgs e)  
  44.     {  
  45.         if (NavigatingFrom != null)  
  46.         {  
  47.             NavigatingFrom(this, e);  
  48.         }  
  49.     }  
  50.    
  51.     /// <summary>  
  52.     /// Occurs when [navigating from].  
  53.     /// </summary>  
  54.     public event NavigatingCancelHandler NavigatingFrom;  
  55.    
  56.     /// <summary>  
  57.     /// Occurs when [navigated from].  
  58.     /// </summary>  
  59.     public event NavigationEventHandler NavigatedFrom;  
  60.    
  61.     /// <summary>  
  62.     /// Occurs when [navigated to].  
  63.     /// </summary>  
  64.     public event NavigationEventHandler NavigatedTo;  
  65.    
  66.     /// <summary>  
  67.     /// Occurs when [fragment navigation].  
  68.     /// </summary>  
  69.     public event FragmentNavigationHandler FragmentNavigation;  
  70. }  
After that, StepsUserControl and ResourcesUserControl will be a ModernUserControl as in the following:
  1. <controls:ModernUserControl x:Class="ModernUIForWPFSample.Navigation.Views.StepsControl"  
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  5.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  6.              xmlns:controls="clr-namespace:ModernUIForWPFSample.Navigation__MVVM_.Controls"  
  7.              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  8.              d:DesignHeight="300"  
  9.              d:DesignWidth="600"  
  10.              mc:Ignorable="d"  
  11.              DataContext="{Binding StepsViewModel, Source={StaticResource Locator}}">  
  12.     <i:Interaction.Triggers>  
  13.          <i:EventTrigger EventName="NavigatedTo">  
  14.             <i:InvokeCommandAction Command="{Binding NavigatedToCommand}" />  
  15.         </i:EventTrigger>  
  16.         <i:EventTrigger EventName="NavigatedFrom">  
  17.             <i:InvokeCommandAction Command="{Binding NavigatedFromCommand}" />  
  18.         </i:EventTrigger>  
  19.         <i:EventTrigger EventName="NavigatingFrom">  
  20.             <i:InvokeCommandAction Command="{Binding NavigatingFromCommand}" />  
  21.         </i:EventTrigger>  
  22.         <i:EventTrigger EventName="FragmentNavigation">  
  23.             <i:InvokeCommandAction Command="{Binding FragmentNavigationCommand}" />  
  24.         </i:EventTrigger>  
  25.         <i:EventTrigger EventName="Loaded">  
  26.             <i:InvokeCommandAction Command="{Binding LoadedCommand}" />  
  27.         </i:EventTrigger>  
  28.         <i:EventTrigger EventName="IsVisibleChanged">  
  29.             <i:InvokeCommandAction Command="{Binding IsVisibleChangedCommand}" />  
  30.         </i:EventTrigger>  
  31.     </i:Interaction.Triggers>  
  32.     <Grid>  
  33.         <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">  
  34.             Steps:  
  35.             <LineBreak />  
  36.             1st Install the ModernUI from Nuget  
  37.             <LineBreak />  
  38.             2nd Define in App.xaml the resources for ModernUI.xaml and ModernUI.Light.xaml  
  39.             <LineBreak />  
  40.             3rd Change the MainWindow: Replace the tag "Window" to ModernWindow  
  41.             <LineBreak />  
  42.             4th Define the content for the MainWindow using TitleLinks, MenuLinkGroups, LinkGroup...  
  43.             <LineBreak />  
  44.             5th Define which content is shown when the application start, by using the ContentSource  
  45.             <LineBreak />  
  46.             6th For each content (in this case for StepsControl and ResourcesControl) must implement the interface IContent   
  47.             <LineBreak />  
  48.             7th For each navigation method (OnFragmentNavigation, OnNavigatedFrom, OnNavigatedTo and OnNavigatingFrom) add the behavior you want  
  49.             <LineBreak />  
  50.             <LineBreak />  
  51.             Note: For change the appearance use  AppearanceManager class  
  52.         </TextBlock>  
  53.     </Grid>  
  54. </controls:ModernUserControl>  
For help in th MVVM pattern implementation we will use the MVVMLight Toolkit and we will have two view models (StepsViewModel and ResourcesViewModel).

Here are the class diagrams.

MVC

ViewModelLocator will help in binding the view model to the view and is where we set up the dependencies for the dependency injection.

When we run the application the output will be something like:

ModernUserControl - OnNavigatedTo
StepsViewModel - LoadData
ModernUserControl - OnNavigatingFrom
StepsViewModel - NavigatingFrom
ModernUserControl - OnNavigatingFrom event called
ModernUserControl - OnNavigatedFrom
StepsViewModel - NavigatedFrom
ModernUserControl - OnNavigatedFrom event called
ModernUserControl - OnNavigatedTo
StepsViewModel - LoadData
ResourcesViewModel - LoadData
ModernUserControl - OnNavigatingFrom
ResourcesViewModel - NavigatingFrom
ModernUserControl - OnNavigatingFrom event called
ModernUserControl - OnNavigatedFrom
ResourcesViewModel - NavigatedFrom
ModernUserControl - OnNavigatedFrom event called
ModernUserControl - OnNavigatedTo
StepsViewModel - NavigatedTo
ModernUserControl - OnNavigatedTo event called
ResourcesViewModel - LoadData
StepsViewModel - LoadData

With it, we can conclude that when we use events, the NavigateTo event is not raised the first time the control is shown, because the NavigateTo event wasn´t subscribed to when the first navigation occurs.

See others solutions for Navigation in ModernUI applications.

 

Source Code

Get the source code for this sample in github.

Visual Studio Extension used