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?

kkyr
  • 3,785
  • 3
  • 29
  • 59
  • 1
    I think you're actually wanting [DataTemplateSelector](https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector%28v=vs.110%29.aspx) – Chris W. Feb 18 '16 at 21:56
  • @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**."_ – kkyr Feb 18 '16 at 21:57
  • Sorry dude, was thinking [ItemTemplateSelector](https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector%28v=vs.110%29.aspx), 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. – Chris W. Feb 18 '16 at 22:01
  • You can also use DataTemplateSelector for that. [MSDN ref.](https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx) and [Stackoverflow ref.](https://stackoverflow.com/a/5644533/1848489) – garenyondem Feb 19 '16 at 09:45

1 Answers1

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>
Amadeusz Wieczorek
  • 3,139
  • 2
  • 28
  • 32
  • Works perfectly thanks, you omitted the curly braces however ({x:Type local:ClassOne}). Any idea why what I was using wasn't working? – kkyr Feb 18 '16 at 22:01
  • 5
    @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`. – Clemens Feb 18 '16 at 22:05
  • 2
    `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](https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype%28v=vs.110%29.aspx) states it takes `object` and examples don't use `x:Type` – Amadeusz Wieczorek Feb 18 '16 at 22:06
  • can this be done in uwp same way ? – IronHide Oct 07 '21 at 06:35