0

I have something like this in my XAML:

<TreeView DataContext="{Binding Source={StaticResource Locator}}" ItemsSource="{Binding SomeTree.TopLevelItems}">
    <TreeView.Resources>
        <DataTemplate DataType="{x:Type vm:ILeaf}">
            <CheckBox Content="{Binding Name}" IsThreeState="False" IsChecked="{Binding IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type vm:IGroup}" ItemsSource="{Binding Children}">
            <CheckBox Content="{Binding Name}" IsThreeState="True" IsChecked="{Binding IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

vm: is defined accordingly:

xmlns:vm="clr-namespace:My.ViewModels.MyTree"

And the MyTree namespace contains the interfacesIGroup and ILeaf.

The SomeTree.TopLevelItems is an enumerable of IGroups and ILeafs (it is populated dynamically).

Now, my TreeView should display a tree of checkboxes accordingly, but it is only displaying the top-level elements of the items source, is NOT applying the data template, and calls ToString() on the elements instead.

The other post which mentions the same problem does not apply here, I already checked that.

What am I missing / doing wrong?

Community
  • 1
  • 1
rabejens
  • 7,594
  • 11
  • 56
  • 104
  • 2
    If I remember correctly you can't use DataTemplates for Interfaces (multiple could apply). Possible workaround here: [How to bind DataTemplate datatype to interface?](http://stackoverflow.com/questions/15023441/how-to-bind-datatemplate-datatype-to-interface) Alternative Solution: Implement your own [`DataTemplateSelector`](https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx) – Manfred Radlwimmer Nov 08 '16 at 10:23
  • I changed this already and put the correct classes in the {x:Type} but it didn't change anything. Or does the list in a view model also have to be of a non-interface type? – rabejens Nov 08 '16 at 10:26
  • 2
    As @ManfredRadlwimmer spotted, you can't use interfaces for datatemplates (just think about problem: which one should be picked if given object implement both?). See [this](https://social.msdn.microsoft.com/Forums/vstudio/en-US/1e774a24-0deb-4acd-a719-32abd847041d/data-templates-and-interfaces?forum=wpf) topic for related disccussion. Typical solution is to use template selectors. – Sinatr Nov 08 '16 at 10:27
  • Thanks for your answers, I will change this to use real classes instead. Strangely enough, I did the same with a `TabControl` where it worked. – rabejens Nov 08 '16 at 10:36
  • I redesigned it, and am now using an abstract class for the common stuff all my tree items have, and it now works flawlessly. Thanks for pointing this out. – rabejens Nov 08 '16 at 11:17

1 Answers1

1

Templates only work off concrete classes not Interfaces,

this is a feature as if you have 2 interfaces on 1 class which template should it select?

as the system can't know then your not allowed to do it

See full MS response here https://social.msdn.microsoft.com/Forums/vstudio/en-US/1e774a24-0deb-4acd-a719-32abd847041d/data-templates-and-interfaces?forum=wpf

Instead use a DataTemplateSelector rather than the Type look up, this way you can tell the system how to interpret multi interface situation

public class TaskListDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate
        SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if (element != null && item != null && item is Task)
        {
            Task taskitem = item as Task;

            if (taskitem.Priority == 1)
                return
                    element.FindResource("importantTaskTemplate") as DataTemplate;
            else
                return
                    element.FindResource("myTaskTemplate") as DataTemplate;
        }

        return null;
    }
}
MikeT
  • 5,398
  • 3
  • 27
  • 43