DarioSantarelli.Blog(this);

[WPF] Inheritance and DataTemplates

Posted by dariosantarelli on July 28, 2011

In this post I will show how different DataTemplates related to a hierarchy of classes can be nested and, therefore, reused. The concept is very simple, but its applications in a real scenario could be not so trivial!

Let’s assume to have a base ViewModel useful for editing and saving an object of your model. If the object class is subject to some derivations, maybe you’d like to derive your base ViewModel too in order to fulfill the model inheritance hierarchy. Moreover, most probably you have to define different editing views taking into account the whole inheritance hierarchy. In that case, maybe you’d like to reuse more XAML as possible.

So, let’s assume to have a base abstract Customer class and some concrete specializations, like EducationCustomer and GovernmentCustomer (see image below).   Customer class hierarchyThen, we design ViewModels in order to edit concrete instances of Customer class. In the class diagram below you can see a base ItemEditViewModel<T> which consists in a simple generic ViewModel which exposes a generic Item to be modified and a SaveCommand to persist it somewhere. The class also defines an abstract method OnCanSaveItem() which a concrete implementation must override in order to specify its own validation rules.   ViewModel hierarchy

public abstract class CustomerEditViewModel<T> : ItemEditViewModel<T> where T : Customer
{
 public CustomerEditViewModel(T customer) : base(customer) { }
 public CustomerEditViewModel() { } 

 protected override bool OnCanSaveItem() 
 {
 if (Item == null)  return false; 
 return (!string.IsNullOrWhiteSpace(Item.Name) && !string.IsNullOrWhiteSpace(Item.Email)); 
 } 
}

public class EducationCustomerEditViewModel : CustomerEditViewModel<EducationCustomer> 
{
 public EducationCustomerEditViewModel() : base() { }
 public EducationCustomerEditViewModel(EducationCustomer customer) : base(customer) { } 

 protected override bool OnCanSaveItem() 
 {
 if (!base.OnCanSaveItem()) return false;
 else return (!string.IsNullOrWhiteSpace(Item.SchoolName)); 
 } 
}  

public class GovernmentCustomerEditViewModel : CustomerEditViewModel<GovernmentCustomer>
{
  public GovernmentCustomerEditViewModel() : base() { }
  public GovernmentCustomerEditViewModel(GovernmentCustomer customer) : base(customer) { }

  protected override bool OnCanSaveItem()
  {
   if (!base.OnCanSaveItem()) return false;
   else return (!string.IsNullOrWhiteSpace(Item.AgencyName));
  }
}

Ok, we have just defined model and viewmodels. Now the interesting part! Our datatemplates could share some portions of XAML (e.g. the edit DataTemplate of the GovernmentCustomer is quite identical to the DataTemplate of the EducationCustomer, but it differs from the former just for a field). So, how can we reuse DataTemplates? First, we can define the edit DataTemplate for the base Customer class…

<DataTemplate x:Key="customerEditTemplate" DataType="{x:Type m:Customer}">
  <Grid>
    ...
    <TextBlock Text="Name" ... />
    <TextBox Text="{Binding Path=Name, Mode=TwoWay}" ... Background="AliceBlue" />
    <TextBlock Text="Email" ... />
    <TextBox Text="{Binding Path=Email, Mode=TwoWay}" ... Background="AliceBlue" />
  </Grid>
</DataTemplate>

 
and then, we can reuse the XAML above in the edit DataTemplate for the GovernmentCustomer and the EducationCustomer.

<DataTemplate x:Key="governmentCustomerEditTemplate" DataType="{x:Type m:GovernmentCustomer}">
  <StackPanel>
    <ContentPresenter ContentTemplate="{StaticResource customerEditTemplate}" />
    <Grid>
    ...
     <TextBlock Text="Agency" ... />
     <TextBox Text="{Binding Path=AgencyName, Mode=TwoWay}" ... Background="LightPink" />
   </Grid>
  </StackPanel>
</DataTemplate>

<DataTemplate x:Key="educationCustomerEditTemplate" DataType="{x:Type m:EducationCustomer}">
  <StackPanel>
    <ContentPresenter ContentTemplate="{StaticResource customerEditTemplate}" />
    <Grid>
      ...
      <TextBlock Text="School" ... />
      <TextBox Text="{Binding Path=SchoolName, Mode=TwoWay}" ... Background="Yellow" />
    </Grid>
  </StackPanel>
</DataTemplate>

 
OK, that’s all. Finally, a simple view can be implemented as below…

<Window ...>
  <Window.Resources>
    <m:GovernmentCustomer x:Key="governmentCustomer" />
    <m:EducationCustomer x:Key="educationCustomer" />
    <vm:GovernmentCustomerEditViewModel x:Key="governmentCustomerEditVM" Item="{StaticResource governmentCustomer}" />
    <vm:EducationCustomerEditViewModel x:Key="educationCustomerEditVM" Item="{StaticResource educationCustomer}" />
  </Window.Resources>

 

  <StackPanel DataContext="{StaticResource governmentCustomerEditVM}" Margin="10">
    <ContentPresenter Content="{Binding Path=Item}" ContentTemplate="{StaticResource governmentCustomerEditTemplate}" />
    <Button Content="Save"Command="{Binding Path=SaveItemCommand}"... />
  </StackPanel>
</Window>

 
As you can see, in this example the edit DataTemplate is referenced by key, but in a real scenario you can define your own mechanism to bind the right ViewModel to a DataTemplate for the Item to be edited and saved. In this example, the output result is the following

EducationCustomer edit WindowGovernmentCustomer edit Window

HTH

Advertisements

One Response to “[WPF] Inheritance and DataTemplates”

  1. ron said

    what is the m in “{x:Type m:Customer}”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: