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:
-
-
-
- public partial class StepsControl : IContent
- {
-
-
-
- public StepsControl()
- {
- InitializeComponent();
- }
-
-
-
-
-
- public void OnFragmentNavigation(FragmentNavigationEventArgs e)
- {
- Debug.WriteLine("StepsControl- OnFragmentNavigation");
- }
-
-
-
-
-
- public void OnNavigatedFrom(NavigationEventArgs e)
- {
- Debug.WriteLine("StepsControl -OnNavigatedFrom");
- }
-
-
-
-
-
- public void OnNavigatedTo(NavigationEventArgs e)
- {
- Debug.WriteLine("StepsControl- OnNavigatedTo");
- }
-
-
-
-
-
-
-
-
-
-
- public void OnNavigatingFrom(NavigatingCancelEventArgs e)
- {
- Debug.WriteLine("StepsControl- OnNavigatingFrom");
- }
- }
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:
- public void OnNavigatedTo(NavigationEventArgs e)
- {
- var viewModel = DataContext as MyViewModel;
- if (viewModel != null)
- {
- viewModel.DoSomething();
- }
- }
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:
- public class ModernUserControl : UserControl, IContent
- {
-
-
-
-
- public void OnFragmentNavigation(FragmentNavigationEventArgs e)
- {
- if (FragmentNavigation != null)
- {
- FragmentNavigation(this, e);
- }
- }
-
-
-
-
-
- public void OnNavigatedFrom(NavigationEventArgs e)
- {
- if (NavigatedFrom != null)
- {
- NavigatedFrom(this, e);
- }
- }
-
-
-
-
-
- public void OnNavigatedTo(NavigationEventArgs e)
- {
- if (NavigatedTo != null)
- {
- NavigatedTo(this, e);
- }
- }
-
-
-
-
-
- public void OnNavigatingFrom(NavigatingCancelEventArgs e)
- {
- if (NavigatingFrom != null)
- {
- NavigatingFrom(this, e);
- }
- }
-
-
-
-
- public event NavigatingCancelHandler NavigatingFrom;
-
-
-
-
- public event NavigationEventHandler NavigatedFrom;
-
-
-
-
- public event NavigationEventHandler NavigatedTo;
-
-
-
-
- public event FragmentNavigationHandler FragmentNavigation;
- }
After that, StepsUserControl and ResourcesUserControl will be a ModernUserControl as in the following:
- <controls:ModernUserControl x:Class="ModernUIForWPFSample.Navigation.Views.StepsControl"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:controls="clr-namespace:ModernUIForWPFSample.Navigation__MVVM_.Controls"
- xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
- d:DesignHeight="300"
- d:DesignWidth="600"
- mc:Ignorable="d"
- DataContext="{Binding StepsViewModel, Source={StaticResource Locator}}">
- <i:Interaction.Triggers>
- <i:EventTrigger EventName="NavigatedTo">
- <i:InvokeCommandAction Command="{Binding NavigatedToCommand}" />
- </i:EventTrigger>
- <i:EventTrigger EventName="NavigatedFrom">
- <i:InvokeCommandAction Command="{Binding NavigatedFromCommand}" />
- </i:EventTrigger>
- <i:EventTrigger EventName="NavigatingFrom">
- <i:InvokeCommandAction Command="{Binding NavigatingFromCommand}" />
- </i:EventTrigger>
- <i:EventTrigger EventName="FragmentNavigation">
- <i:InvokeCommandAction Command="{Binding FragmentNavigationCommand}" />
- </i:EventTrigger>
- <i:EventTrigger EventName="Loaded">
- <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
- </i:EventTrigger>
- <i:EventTrigger EventName="IsVisibleChanged">
- <i:InvokeCommandAction Command="{Binding IsVisibleChangedCommand}" />
- </i:EventTrigger>
- </i:Interaction.Triggers>
- <Grid>
- <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">
- Steps:
- <LineBreak />
- 1st Install the ModernUI from Nuget
- <LineBreak />
- 2nd Define in App.xaml the resources for ModernUI.xaml and ModernUI.Light.xaml
- <LineBreak />
- 3rd Change the MainWindow: Replace the tag "Window" to ModernWindow
- <LineBreak />
- 4th Define the content for the MainWindow using TitleLinks, MenuLinkGroups, LinkGroup...
- <LineBreak />
- 5th Define which content is shown when the application start, by using the ContentSource
- <LineBreak />
- 6th For each content (in this case for StepsControl and ResourcesControl) must implement the interface IContent
- <LineBreak />
- 7th For each navigation method (OnFragmentNavigation, OnNavigatedFrom, OnNavigatedTo and OnNavigatingFrom) add the behavior you want
- <LineBreak />
- <LineBreak />
- Note: For change the appearance use AppearanceManager class
- </TextBlock>
- </Grid>
- </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.
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.