Selecting a data template based on type
Asked Answered
L

1

16

I've declared the following types:

public interface ITest { }
public class ClassOne : ITest { }
public class ClassTwo : ITest { }

In my viewmodel I'm declaring and initializing the following collection:

public class ViewModel
{
    public ObservableCollection<ITest> Coll { get; set; } = new ObservableCollection<ITest>
    {
        new ClassOne(),
        new ClassTwo()
    };  
}

In my view I'm declaring the following ItemsControl

<ItemsControl ItemsSource="{Binding Coll}">
    <ItemsControl.Resources>
        <DataTemplate DataType="local:ClassOne">
            <Rectangle Width="50" Height="50" Fill="Red" />
        </DataTemplate>
        <DataTemplate DataType="local:ClassTwo">
            <Rectangle Width="50" Height="50" Fill="Blue" />
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

What I expect to see is a red square followed by a blue square, instead what I see is the following:

enter image description here

What am I doing wrong?

Longitudinal answered 18/2, 2016 at 21:51 Comment(4)
I think you're actually wanting DataTemplateSelectorDebate
@ChrisW. Directly from that link: "... create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object. Note that if you have objects of different types you can set the DataType property on the DataTemplate."Longitudinal
Sorry dude, was thinking ItemTemplateSelector, I probably shouldn't be on here anyway, first nice day out since winter and my mind is elsewhere, I don't think I even actually looked at the whole question lol. Spring fever, cheers.Debate
You can also use DataTemplateSelector for that. MSDN ref. and Stackoverflow ref.Malony
D
28

Your issue might be caused by finnicky workings of XAML. Specifically, you need to pass Type to DataType, but you were passing a string with the name of the type.

Use x:Type to decorate the value of DataType, like so:

<ItemsControl ItemsSource="{Binding Coll}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type local:ClassOne}">
            <Rectangle Width="50" Height="50" Fill="Red" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ClassTwo}">
            <Rectangle Width="50" Height="50" Fill="Blue" />
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>
Diacid answered 18/2, 2016 at 21:59 Comment(4)
Works perfectly thanks, you omitted the curly braces however ({x:Type local:ClassOne}). Any idea why what I was using wasn't working?Longitudinal
@kyriacos_k Yours wasn't working because the DataTemplate.DataType property is of type object (as opposed to e.g. Style.TargetType, which is of type Type). Hence local:ClassOne is interpreted as string and not implicitly converted to Type.Facing
x:Type acts just like typeof() operator, so you pass in to DataType a Type instead of a name of your class. - even though documentation states it takes object and examples don't use x:TypeDiacid
can this be done in uwp same way ?Semester

© 2022 - 2024 — McMap. All rights reserved.