DarioSantarelli.Blog(this);

Archive for July, 2011

[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

Posted in WPF | 1 Comment »