Templates, Styles, and Polymorphism

This blog post examines the difference between how DataTemplates and Styles are applied to instances of related classes.  In a nutshell, typed DataTemplates support polymorphism while typed Styles do not.

If you create a DataTemplate where its DataType property is set to a base type it will be used to render an instance of a class which derives from the base type.  In that sense, DataTemplates support polymorphism.  Of course, if you also have another DataTemplate which specifically targets the subclass then that template will be used instead.

On the other hand, a typed Style (i.e. a Style with no x:Key) whose TargetType is set to the base type will not be applied to elements of the derived type.  Styles do not support polymorphism.  For a typed Style to be applied to an object, the Style’s TargetType must exactly match the type of the object.

[EDIT: As Jan Kucera keenly pointed out in a comment below, if you give an x:Key to a Style which targets a base type and then assign that Style to an instance of a subclass’s Style property, the Style will be applied to the subclass instance.  This means that there seems to be an inconsistency as to how Styles are applied “polymorphically.”  It works if you apply them explicitly to an element, but a typed Style will not be applied to a subclass of its TargetType.]

I was not aware of this difference until recently.  I spent quite a while tracking down what was rendering a particular data object, and eventually realized that the template I was looking for had its DataType set to a base class of the object being displayed.  After realizing that DataTemplates support polymorphism I tested if Styles do as well, and discovered that they do not.

I think the best way to convey this difference is by showing a simple example.  Here are the classes used in the demo app:

Templates Styles and Polymorphism (classes)

Here is the XAML which creates an instance of Foo2 and Button2, and applies a template and style to them:

Templates Styles and Polymorphism (XAML)

If you run the demo application with the XAML seen above, the UI looks like this:

Templates Styles and Polymorphism (screenshot 1)

As you can see based on the XAML seen previously, the Button2 instance is not affected by the Style which targets the Button class.  However, the Foo2 object is rendered by the DataTemplate whose DataType is set to the Foo base class. 

If we were to uncomment the additional DataTemplate and Style seen in the XAML above, the UI would look like this:

Templates Styles and Polymorphism (screenshot 2)

The Button2 and Foo2 are colored red in this situation because the presence of a DataTemplate and Style specific to those types are present at runtime.

You can download the demo app here: Templates Styles and Polymorphism (demo app)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.

7 Responses to Templates, Styles, and Polymorphism

  1. Karl Shifflett says:

    Josh,

    Great post! Thank you for sharing this with us.

    Now the question is, “is this a bug or did Microsoft build this in and why?” Wonder if future releases will honor the polymorphic DataTemplate.

    Cheers,

    Karl

  2. Jan Kucera says:

    However, you’re allowed to use Style=”{StaticResource keyToButtonStyle}” on Button2, as I’m able to use

    on any element which inherits Control.

    Maybe with similar idea you could use something like {StaticResource {x:Type Button}}.

    Do you know how to workaround this limitation? I’m trying to change the appearance of the focus rectangle – https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1804225&SiteID=1 – but my original idea does not work because of this.

  3. Jan Kucera says:

    Hm, tags disappeared.. …able to use
    <Style x:Key=”MyStyle”>
    <Setter Property=”Control.Padding” Value=”10″ />
    </Style>

  4. Josh Smith says:

    Karl,

    I was wondering the same thing, but didn’t want to include my speculations in the post. If it is a bug, then I doubt that MSFT will “fix it” for the next release. That would break a lot of peoples WPF apps, so they might add a property to Style called something like CanBeUsedPolymorphically. Man, that’s a horrible name!😀

    Josh

  5. Josh Smith says:

    Jan,

    That’s an interesting point. So if you explicitly assign the Button2 a Style which is targeting the Button class (not Button2 class) then it will be applied to the properties of Button2. Wow, this is really starting to smell like a bug in how typed Styles are applied.

    Sorry, I don’t currently know a workaround which will help solve your problem with the focus rect.

    Josh

  6. Eric Hahn says:

    I believe Style also has a BasedOn property which allows you to explicitly reference another “base” style? Might that enable a poor-man’s inheritance?

    In this (still bogus) scenario, you would have a potentially-empty Style for Button2 which was BasedOn the Style for Button, but had Button2 as its target type? Then you wouldn’t need to muck with the markup for Button2 instances.

    Disclaimer: I’ve not tried this.

  7. Josh Smith says:

    Eric,

    That is true, Style has the BasedOn property. However, using that technique for something broad sweeping, such as Jan’s need to set the FocusVisualStyle for *all* elements, would prove quite tedious and error prone because it requires a typed Style specific to each type of element in the UI. If we could create one typed Style whose TargetType is FrameworkElement, and have that Style apply to all elements, then the problem would be easily solved.

    Josh

%d bloggers like this: