Simple navigation technique in WPF using MVVM
Introduction:
In WPF application navigation plays a vital role. Performing navigation using MVVM is little tricky. In this article we will see how to navigate different UserControls in a ContentControl.
Scenario:
Let us take typical application which talks about employees. Say for example it has two UserControls one for employee and the other one for departments. The main window layout has navigation buttons on the left handle side and a ContentControl on the right hand side to display the corresponding UserControl.
Solution:
In MVVM navigation can be achieve by hooking together DataTemplate with UserControl, ContentControl and corresponding ViewModel. Refer the below detailed steps.
UserControls:
Create Two UserControls EmployeeView and DepartmentView. Also Create Dummy ViewModels for both.
<UserControl x:Class="DataTemplateSO_Learning.EmployeeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="Employee Details"/>
</Grid>
</UserControl>
<UserControl x:Class="DataTemplateSO_Learning.DepartmentView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="Department Details"/>
</Grid>
</UserControl>
class EmployeeViewModel
{
}
class DepartmentViewModel
{
}
DataTemplates:
Create a DataTemplate of type EmployeeViewModel and it should contain EmployeeView UserControl inside it. Important thing is you should specify any key to the DataTemplates, since these DataTemplates are going to get queried by their DataType.
<DataTemplate DataType="{x:Type local:EmployeeViewModel}">
<local:EmployeeView/>
</DataTemplate>
Similarly for Departments.
<DataTemplate DataType="{x:Type local:DepartmentViewModel}">
<local:DepartmentView/>
</DataTemplate>
MainWindow Layout:
Add the above DataTemplates as MainWindow resources. Also add two Buttons for navigating to Employee and Department UserControl correspondingly. Add a ContentControl which will act as a Container and once navigation is done corresponding UserControl will be placed inside this ContentControl.
<Window x:Class="DataTemplateSO_Learning.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataTemplateSO_Learning"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:EmployeeViewModel}">
<local:EmployeeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:DepartmentViewModel}">
<local:DepartmentView/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<StackPanel x:Name="navigation" DockPanel.Dock="Left">
<Button Content="Employee" Command="{Binding EmpCommand}"></Button>
<Button Content="Department" Command="{Binding DeptCommand}"></Button>
</StackPanel>
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
</DockPanel>
</Window>
NavigationViewModel:
It should have two commands for navigation. It should a property of type object which will be assigned with corresponding ViewModel based on the button selection.
class NavigationViewModel : INotifyPropertyChanged
{
public ICommand EmpCommand { get; set; }
public ICommand DeptCommand { get; set; }
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set { selectedViewModel = value; OnPropertyChanged("SelectedViewModel"); }
}
public NavigationViewModel()
{
EmpCommand = new BaseCommand(OpenEmp);
DeptCommand = new BaseCommand(OpenDept);
}
private void OpenEmp(object obj)
{
SelectedViewModel = new EmployeeViewModel();
}
private void OpenDept(object obj)
{
SelectedViewModel = new DepartmentViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
Need to assign the NavigationViewModel as DataContext of MainWindow.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new NavigationViewModel();
}
}
When the employee button is clicked, it will assign the SelectedViewModel property with the EmployeeViewModel and hence in the ContentControl the content will be set to the DataTemplate of the DataType EmployeeViewModel and the EmployeeView is loaded in the ContentControl.
That’s It. We have done a Simple Navigation in WPF application using MVVM.
Sample: NavigationMVVM