C# – Menu in NavigationWindow tutorial

NavigationWindow derives from System.Windows.Window and extends this class with ability for content navigation and navigation history. The content can be any type of .Net Framework and HTML sites. If you’re using XBAPs (www.xbap.org) you can realize that he uses IE as his kernel and NavigationWindow as his navigator. XBAP’s main window has reference to NavigationWindow and the navigation history is managed and integrated between NavigationWindow and IE to provide a better integrated user experience.
Building a NavigationWindow application is pretty simple. Just create a new project of WPF Form and then replace Window class to NavigationWindow as below

Old XAML

<Window x:Class="NavigationWindow.MainWindow"
        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"
...
</Window>

New XAML

<NavigationWindow x:Class="NavigationWindow.MainWindow"
        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"
...
</NavigationWindow>

Old C# Code

public partial class MainWindow : Window
{
	...
}

New C# Code

public partial class MainWindow : System.Windows.Navigation.NavigationWindow
{
	...
}

Then we have a window with a navigation bar on the top of window without writing any code. This window will contain all of our pages. Each page will present a step in a complete sequential workflow.

NavigationWindow

Now we add some pages so that we can navigate between them to demonstrate how navigator works. To keep it simple, I just add some very simple pages with some URI to show how we can jump to desired pages.

1. First Page

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="5*"/>
		<RowDefinition Height="5*" />
	</Grid.RowDefinitions>
		
	<TextBlock Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="I am the first page" />
	<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
		Click <Hyperlink NavigateUri="SecondPage.xaml">here</Hyperlink> to go to Page 2
	</TextBlock>
</Grid>

First Page

2. Second Page

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="4*"/>
		<RowDefinition Height="3*" />
		<RowDefinition Height="3*" />
	</Grid.RowDefinitions>
	<TextBlock Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="I am the second page." />
	<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
		Click <Hyperlink NavigateUri="FirstPage.xaml">here</Hyperlink> to go back
	</TextBlock>
	<TextBlock Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">
		Click <Hyperlink NavigateUri="ThirdPage.xaml">here</Hyperlink> to go next
	</TextBlock>
</Grid>

Second Page

3.Third Page

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="4*"/>
		<RowDefinition Height="3*" />
		<RowDefinition Height="3*" />
	</Grid.RowDefinitions>
	<TextBlock Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="I am the third page." />
	<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
		Click <Hyperlink NavigateUri="SecondPage.xaml">here</Hyperlink> to go back
	</TextBlock>
	<TextBlock Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">
		Click <Hyperlink NavigateUri="FirstPage.xaml">here</Hyperlink> to go to first page
	</TextBlock>
</Grid>

Third Page

All pages are on the same level (on same folder) therefore I can call them directly with NavigateUri. The history was displayed exactly like in IE.

Navigation Url
If we want to add a menu available for all pages, just define one on the top of NavigatorForm.Content.

<NavigationWindow.Content>
	<Grid>
		<Menu x:Name="mnuTop" Height="25" VerticalAlignment="Top">
			<MenuItem Header="First" Command="{Binding MenuItemClick}" CommandParameter="FirstPage.xaml"/>
			<MenuItem Header="Second" Command="{Binding MenuItemClick}" CommandParameter="SecondPage.xaml" />
			<MenuItem Header="Third" Command="{Binding MenuItemClick}" CommandParameter="ThirdPage.xaml"/>
		</Menu>
		<Border BorderThickness="1" Margin="0,25,0,0" BorderBrush="Black">
			<Frame Source="{Binding CurrentSelectedPage, Mode=TwoWay}"/>
		</Border>
	</Grid>
</NavigationWindow.Content>

So with the NavigationWindow, we have a full supported navigator with content and history without “writing any source code” for that. Yes, not really “no code”, I am using MVVM.Light Framework to generate the code for me. The Frame.Source property is bound with a property of ViewModel. All MenuItems commands will be bound with a common action and when a menu item clicked, he’ll call this action with a given parameter in CommandParameter property. From the side of action, he need to be declared as a function with one input parameter type of object to receive value of this parameter.

private RelayCommand<object> menuItemClickCommand;
public ICommand MenuItemClick
{
	get
	{
		if (menuItemClickCommand == null)
			menuItemClickCommand = new RelayCommand<object>(o => HandleMenuItemClick(o));
		return menuItemClickCommand;
	}
}

private void HandleMenuItemClick(object e)
{
	CurrentSelectedPage = e.ToString();
}

NavigationWindow with Menu

There is only one notice that the F5 key is reserved for refresh the content of Frame in NavigationWindow.Content. Therefore don’t use this Key for any action in your application because it was hooked by NavigationWindow. This demo was written with MVVM.Light Framework and the source code can be downloaded here “NavigationWindow