Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to use data-template inheritance in WPF?

Is it possible to have DataTemplate composition or inheritance (similar to "BasedOn" in Styles)? There are 2 instances where I need that.

  1. For inherited classes: I have a base class with several inherited classes. I don't want to duplicate the base class template in each of the derived class's DataTemplate.

  2. Different Views: for the same class I want to define a datatemplate, and then add to that template as appropriate. Ex. the base template will display the data in the object and then i want different templates that can perform different actions on the object, while displaying the data (inheriting the base template).

like image 763
Fragilerus Avatar asked Dec 14 '10 20:12

Fragilerus


People also ask

What is difference between a ControlTemplate and a DataTemplate in WPF?

A ControlTemplate will generally only contain TemplateBinding expressions, binding back to the properties on the control itself, while a DataTemplate will contain standard Binding expressions, binding to the properties of its DataContext (the business/domain object or view model).

What is a DataTemplate in WPF?

DataTemplate is about the presentation of data and is one of the many features provided by the WPF styling and templating model. For an introduction of the WPF styling and templating model, such as how to use a Style to set properties on controls, see the Styling and Templating topic.


2 Answers

The only thing that I have found do to for this kind of thing is this:

<DataTemplate x:Key="BaseClass">   <!-- base class template here --> </DataTemplate> <DataTemplate DataType="{x:Type app:BaseClass}">   <ContentPresenter Content="{Binding}"                      ContentTemplate="{StaticResource BaseClass}"/> </DataTemplate> <DataTemplate DataType="{x:Type app:DerivedClass}">   <StackPanel>     <ContentPresenter Content="{Binding}"                        ContentTemplate="{StaticResource BaseClass}"/>     <!-- derived class extra template here -->   </StackPanel> </DataTemplate> 

Basically this creates a "common" template that can be referenced using a key (BaseClass in this case). Then we define the real DataTemplate for the base class, and any derived classes. The derived class template would then add it's own "stuff".

There was some discussion about this on msdn a while back, but no one came up with a better solution that I saw.

like image 55
Liz Avatar answered Sep 22 '22 15:09

Liz


@Fragilerus and @Liz, actually I think I did come up with something better. Here's another approach that not only avoids the extra ContentPresenter binding, but also removes the need to have to apply a template within a template since the shared content is direct content which is set at compile-time. The only thing that happens at run-time would be the bindings you set inside the direct content. As such, this greatly speeds up the UI when compared to the other solution.

<!-- Content for the template (note: not a template itself) --> <Border x:Shared="False"          x:Key="Foo"          BorderBrush="Red"          BorderThickness="1"          CornerRadius="4">     <TextBlock Text="{Binding SomeProp}" /> </Border>  <DataTemplate x:Key="TemplateA">     <!-- Static resource - No binding needed -->     <ContentPresenter Content="{StaticResource Foo}" />  </DataTemplate>  <DataTemplate x:Key="TemplateB">     <!-- Static resource - No binding needed -->     <ContentPresenter Content="{StaticResource Foo}" /> </DataTemplate> 

Important: Make sure to use the x:Shared attribute on your shared content or this will not work.

The WPF'y Way

The above said, this really isn't the most WPF-friendly way to do what you're after. That can be achieved using the DataTemplateSelector class which does exactly that... select's a data template based on whatever criteria you set.

For instance, you could easily set one up that looks for your known data types and returns the same DataTemplate for both of them, but for all other types, it falls back to the system to resolve the DataTemplate. That's what we actually do here.

Hope this helps! :)

like image 37
Mark A. Donohoe Avatar answered Sep 21 '22 15:09

Mark A. Donohoe