beatnikthedan
beatnikthedan

Reputation: 221

UWP TreeView ItemTemplateSelector not working

The WPF version of this question is here: But it hasn't been answered and I don't know if the UWP TreeView will have the same answer.

I'm trying to add a DataTemplateSelector to the new UWP TreeViews that were just added to windows 10 version 1803 but it isn't working. It is documented here how to use the XAML TreeView Control and even shows how to modify the template to change the Item Datatemplate which works fine. I need to use a datatemplate selector since each of my nodes is using different objects and I need them displayed differently. The TreeView.Node.Content is being set just fine and everything works except it is passing null over to the datatemplateselector in the Object parameter.

Here is my code: (same as the example from Microsoft just with using ItemTemplateSelector)

<Style TargetType="TreeView">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TreeView">
                    <TreeViewList x:Name="ListControl"
                                      ItemTemplateSelector="{StaticResource CardSelector}"
                                      ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                                      CanDragItems="True"
                                      AllowDrop="True"
                                      CanReorderItems="True">
                        <TreeViewList.ItemContainerTransitions>
                            <TransitionCollection>
                                <ContentThemeTransition />
                                <ReorderThemeTransition />
                                <EntranceThemeTransition IsStaggeringEnabled="False" />
                            </TransitionCollection>
                        </TreeViewList.ItemContainerTransitions>
                    </TreeViewList>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Does anyone have any insight or experience on this? My datatemplateselector "CardSelector" works fine and I have been using it in several places without any trouble.

Upvotes: -1

Views: 1548

Answers (2)

Xie Steven
Xie Steven

Reputation: 8621

So the point of my question isn't to get anything that I have working but to see if the TreeViewControl works with a DataTemplateSelector. I only have "CardTemplateSelector" in there because I use it in several other places of my app and I know it works. My question is really a "yes, treeview works with a selector" or "no it doesn't" I'm really looking for someone else to try it with their own test template selector and to let me know if they can get it working. Any specific code from me is not relevant to the question. Just see if you can get it to work with whatever selector you want

Yes. The TreeView work well with ItemTemplateSelector.

I used the all code in the document and create a custom class like the following:

public class Test
{
    public string Name { get; set; }
}

I made another DataTemplate like this:

<DataTemplate x:Key="TreeViewObjDataTemplate">
        <Grid Height="44">
            <TextBlock
                Text="{Binding Content.Name}"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Style="{ThemeResource BodyTextBlockStyle}"/>
        </Grid>
</DataTemplate>

My CardTemplateSelector class is the following:

public class CardTemplateSelector: DataTemplateSelector
{
    public DataTemplate TreeViewItemDataTemplate { get; set; }
    public DataTemplate TreeViewObjDataTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        TreeViewNode treeViewNode = item as TreeViewNode;
        if (treeViewNode.Content is StorageFolder|| treeViewNode.Content is StorageFile)
        {
            return TreeViewItemDataTemplate;
        }
        if (treeViewNode.Content is Test)
        {
            return TreeViewObjDataTemplate;
        }

        return base.SelectTemplateCore(item);
    }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        return SelectTemplateCore(item);
    }
}

I just add the new lines code in MainPage.xaml.cs:

TreeViewNode objnode = new TreeViewNode();
Test test = new Test() {Name="Parent"};
objnode.Content = test;
objnode.IsExpanded = true;
objnode.HasUnrealizedChildren = true;
sampleTreeView.RootNodes.Add(objnode);

The following is the whole xaml page resource code:

    <Page.Resources>
    <DataTemplate x:Key="TreeViewItemDataTemplate">
        <Grid Height="44">
            <TextBlock
                Text="{Binding Content.DisplayName}"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Style="{ThemeResource BodyTextBlockStyle}"/>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="TreeViewObjDataTemplate">
        <Grid Height="44">
            <TextBlock
                Text="{Binding Content.Name}"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Style="{ThemeResource BodyTextBlockStyle}"/>
        </Grid>
    </DataTemplate>

    <local:CardTemplateSelector x:Name="CardTemplateSelector" TreeViewItemDataTemplate="{StaticResource TreeViewItemDataTemplate}" TreeViewObjDataTemplate="{StaticResource TreeViewObjDataTemplate}"></local:CardTemplateSelector>
    
    <Style TargetType="TreeView">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TreeView">
                    <TreeViewList x:Name="ListControl"
                                  ItemTemplateSelector="{StaticResource CardTemplateSelector}"
                                  ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                                  CanDragItems="True"
                                  AllowDrop="True"
                                  CanReorderItems="True">
                        <TreeViewList.ItemContainerTransitions>
                            <TransitionCollection>
                                <ContentThemeTransition />
                                <ReorderThemeTransition />
                                <EntranceThemeTransition IsStaggeringEnabled="False" />
                            </TransitionCollection>
                        </TreeViewList.ItemContainerTransitions>
                    </TreeViewList>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

enter image description here

Upvotes: 1

Michael Bakker
Michael Bakker

Reputation: 149

There seems to be confusion about where to apply the DataTemplate. And the all important TargetType is ignored.

If you want a handle on the data item in your custom DataTemplateSelector, you need to:

OPTION 1

  • Apply the DataTemplateSelector on TreeView.ItemTemplateSelector
  • Make sure that the DataTemplates have TreeViewNode as the target type.

Only then the data item of the TreeViewNode is supplied to the SetTemplateCore(object item) and SetTemplateCore(object item, DependencyObject container) overrides of your custom DataTemplateSelector. A working example is found here: Pictures and Music library tree view

OPTION 2

  • Apply the DataTemplateSelector on TreeViewItem.ContentTemplateSelector
  • Make sure that the DataTemplates have [YOUR-DATA-TYPE] as the target type
  • In the TreeView.ItemTemplate bind the DataContext AND Content property to [YOUR-DATA-TYPE], i.e.
<TreeView.ItemTemplate>
    <DataTemplate x:DataType="[YOUR-DATA-TYPE]">
        <TreeViewItem DataContext="{Binding}" ... Content="{Binding}">
            <TreeViewItem.ContentTemplateSelector>
                <YourDataTemplateSelector.TemplateA>
                    <DataTemplate x:DataType="[YOUR-DATA-TYPE]">
                        ...
// YourDataTemplateSelector
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        if (item == null) return null;
        return (([YOUR-DATA-TYPE])item).IsSomething ? TemplateA : TemplateB;
    }

Upvotes: 0

Related Questions