One of the cool features of WPF is the way we can define a UI based upon the data type used.
For example, assuming a very simple view model
public class PersonViewModel : ReactiveObject
{
private string firstName;
private string lastName;
private int age;
public string FirstName
{
get { return firstName; }
set { this.RaiseAndSetIfChanged(ref firstName, value); }
}
public string LastName
{
get { return lastName; }
set { this.RaiseAndSetIfChanged(ref lastName, value); }
}
public int Age
{
get { return age; }
set { this.RaiseAndSetIfChanged(ref age, value); }
}
}
We might have a parent view model returning a PersonViewModel type or maybe an ItemsControl that has an ObservableCollection of PersonViewModel types. We can handle the bindings in the standard way but we can also associate a UI with a data type using DataTemplates.
A simple example of this is seem with the following code
<ResourceDictionary>
<Model:PersonViewModel x:Key="model"/>
</ResourceDictionary>
<Button Content="{Binding Source={StaticResource model}}"/>
With the above the button content will display the namespace.objecttype, i.e. MyTestApp.PersonViewModel which is of little use, but if we create a DataTemplate as per the following XAML, we get something more useable
<DataTemplate DataType="{x:Type ta:PersonViewModel}">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} aged {2}">
<Binding Path="FirstName" />
<Binding Path="LastName" />
<Binding Path="Age" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
Now our button will display the “FirstName LastName aged Age” text, where obviously FirstName, LastName and Age are taken from our view model.
Note: You can use a DataTemplate against any ContentControl, so we can see this template used on a button, a label or other control that expects/handles a ContentControl. Whereas the likes of a TextBlock’s Text property expects a string, so this will not work there.
The DataTemplate is also used in the ItemTemplate of a ListBox (for example)
<ListBox ItemsSource="{Binding People}" />
Using the above, where People is an ObservableCollection
<ListBox ItemsSource="{Binding People}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} aged {2}">
<Binding Path="FirstName" />
<Binding Path="LastName" />
<Binding Path="Age" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Along with DataTemplate we can define DataTemplate Triggers, for example
<DataTemplate DataType="{x:Type ta:PersonViewModel}">
<TextBlock x:Name="text">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} aged {2}">
<Binding Path="FirstName" />
<Binding Path="LastName" />
<Binding Path="Age" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<DataTemplate.Triggers>
<Trigger SourceName="text" Property="IsMouseOver" Value="True">
<Setter TargetName="text" Property="Background" Value="GreenYellow" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
So now anything use the DataTemplate will also apply the trigger code to the UI view of this data.