How can you enable auto-DataTemplate selection based on data type like you can with an items control?
Asked Answered
P

1

8

We're writing a very specialized ItemsControl which actually has three ContentPresenter's per 'row', each bound to a different object (think poor-man's grid) instead of the more common one, like a ListBox.

Now with a ListBox if you don't explicitly specify either an ItemTemplate or an ItemTemplateSelector, there seems to be some internal selector that applies the template based purely on data type. However, our ContentPresenter's aren't picking them up. We've also tried switching them to ContentControl's instead, but that hasn't worked either.

Now I know I can simply write my own DataTypeTemplateSelector that does this, but I'm wondering if that functionality is already 'baked in' somewhere considered its used with so many ItemsControl's (ListBox, TreeView, ComboBox', DataGrid, etc.) and according to this MSDN article...

http://msdn.microsoft.com/en-us/library/ms742521.aspx

...it should work by default! But again, it doesn't.

Here's our (pseudo) code...

<UserControl.Resources>

    <!-- These all work when the relevant items are in a ListBox,
         but not with stand-alone ContentPresenters or ContentControls -->

    <DataTemplate DataType="local:SomeTypeA">
        <TextBlock Text="{Binding Converter={c:DataTypeNameConverter}}" Foreground="Blue" />
    </DataTemplate>

    <DataTemplate DataType="local::SomeTypeB">
        <TextBlock Text="{Binding Converter={c:DataTypeNameConverter}}" Foreground="Purple" />
    </DataTemplate>

    <DataTemplate DataType="local::SomeTypeC">
        <TextBlock Text="{Binding Converter={c:DataTypeNameConverter}}" Foreground="Purple" />
    </DataTemplate>

</UserControl.Resources>

<!-- These don't pick up the templates -->
<ContentControl Content="{Binding Field1}" />
<ContentPresenter Content="{Binding Field2}" />

<!-- This however does -->
<ListBox ItemsSource="{Binding AllItems}" 

So... anyone want to take a stab at why not?

Pirouette answered 27/9, 2011 at 19:15 Comment(2)
I have used DataTemplates with ContentControls many times in the past without a problem. Can you post your actual code instead of pseudocode? And does it work if you set DataType equal to {x:Type local:SomeTypeA} instead of just "local:SomeTypeA"?Squama
Rachel, you're right. It does work with the markup-extension x:Type for the reason that H.B. pointed out below... MSFT in their infinite wisdom deemed a property called 'DataType' is of type Object and not of type System.Type so unlike with the 'TargetType' of a style, for a DataTemplate you have to use the markup.Pirouette
I
8

DataType, for whatever crazy reason, is of type Object, the DataTemplates hence have a string set in that property unless you use x:Type.


Edit: There is a very good reason for the property being an object, as always those who can (and do) read are clearly at an advantage:

If the template is intended for object data, this property contains the type name of the data object (as a string). To refer to the type name of the class, use the x:Type Markup Extension. If the template is intended for XML data, this property contains the XML element name. See the documentation remarks for details about specifying a non-default namespace for the XML element.

Interlock answered 27/9, 2011 at 19:51 Comment(1)
Aaaaah! That's why! I'm so used to omitting the x:Type when specifying the TargetType in styles (where I'm assuming it's properly set as type Type) so by omitting it here too, where you're saying the type is Object (and you're right... WTFBBQ, MSFT?!) it instead gets interpreted as a simple string, and therefore never matches! Great catch, especially since you know the 'Why!' (I almost wrote that wasn't needed until I saw your answer.) Wonder if this should be reported as a bug to MS! (Also, rule of thumb: Always use the markup! Clearer and would have worked!) Tx again!Pirouette

© 2022 - 2024 — McMap. All rights reserved.