Connecting Views with View Models

In WPF, there are several ways to connect our Views to their data sources. We've all seen examples of the simplest method of a View setting its DataContext property to itself in its code behind:

public partial class MainWindow : Window 
{ 
  public MainWindow() 
  { 
    InitializeComponent(); 
    DataContext = this; 
  } 
} 

However, this should only ever be used for quick demonstrations and never in our real-world applications. If we need to data-bind to properties declared in a View's code behind, let's say for a particular custom UserControl, then we should use RelativeSource bindings instead. We'll find out more about this in Chapter 4, Becoming Proficient with Data Binding, but for now, let's continue looking at the alternative ways to connect the Views with their data sources.

The next simplest method utilizes the data templating Model that is built into the WPF Framework. This topic will also be covered in much more detail in Chapter 4, Becoming Proficient with Data Binding, but, in short, a DataTemplate is used to inform the WPF Framework how we want it to render data objects of a particular type. The simple example shows how we could define the visual output of our User objects:

<DataTemplate DataType="{x:Type DataModels:User}"> 
  <TextBlock Text="{Binding Name}" /> 
</DataTemplate> 

In this example, the DataType property specifies which type of object this relates to and therefore, which properties the containing XAML bindings have access to. Keeping it simple for now, we just output the name of each User in this DataTemplate. When we data-bind one or more User objects to a UI control that is within the scope of this DataTemplate, they will each be rendered by the WPF Framework as a TextBlock that specifies their name.

When the rendering engine of the WPF Framework comes across a custom data object, it looks for a DataTemplate that has been declared for its type and, if it finds one, it renders the object according to the XAML contained within the relevant template. This means that we can create a DataTemplate for our View Model classes that simply specifies their related View classes as the rendering output:

<DataTemplate DataType="{x:Type ViewModels:UsersViewModel}"> 
  <Views:UsersView /> 
</DataTemplate> 

In this example, we have specified that when the WPF Framework sees an instance of our UserViewModel class, it should render it as one of our UserView classes. At this point, it will set our View Model instance to the DataContext property of the related View implicitly. The only downside to this method is minimal, and is that we have to add a new DataTemplate to our App.xaml file for each of our View-View Model pairs.

This method of connection works View Model first, where we supply the View Model instance and the WPF Framework takes care of the rest. In these cases, we typically use a ContentControl that has its Content property data bound to a ViewModel property, which the application View Models are set to. The WPF Framework notes the type of the View Model that is set and renders it according to its specified DataTemplate:

private BaseViewModel viewModel; 
 
public BaseViewModel ViewModel 
{ 
  get { return viewModel; } 
  set { viewModel = value; NotifyPropertyChanged(); } 
} 
    
... 
    
ViewModel = new UserViewModel(); 
    
...
     
<ContentControl Content="{Binding ViewModel}" /> 

This is the preferred version of View to View Model connections for many, as the WPF Framework is left to take care of most of the details. However, there is another way to construct these connections that adds a layer of abstraction to the process.