Search code examples
c#wpfxamlmvvmhierarchicaldatatemplate

How do you style only the top level items in TreeView?


For the 2nd day I'm scouring the web and have not found a solution. Take an element like this:

<TreeView ItemsSource="{Binding Types}" Width="300">
   <TreeView.Resources>
      <HierarchicalDataTemplate DataType="{x:Type models:Type}"
                                ItemsSource="{Binding SubTypes}">
         <TextBlock Text="{Binding Name}"/>
         <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate DataType="{x:Type SubType}">
               <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
         </HierarchicalDataTemplate.ItemTemplate>
      </HierarchicalDataTemplate>
   </TreeView.Resources>
</TreeView>

I use the Material NuGet library for base styles. Now however I need to disable the hover, select, etc. on the first level items and only allow the selection/hover for the subitems.

But everything I seem to find is about styling the contents of each item or styling everything globally.

A <- remove selection/hover (pref single click too but that's another topic)
  A1 <- maintain original style, hover and select
  A2 <- maintain original style, hover and select
  A3 <- maintain original style, hover and select
B <- remove selection/hover (pref single click too but that's another topic)
  B1 <- maintain original style, hover and select
  B2 <- maintain original style, hover and select
  B3 <- maintain original style, hover and select

Solution

  • Sounds like you don't really want each top-level item to act like a normal TreeViewItem. In that case, why not move the top-level items outside of the TreeView?

    Basically, you'd have an ItemsControl of the top-level items, where the item template acts a bit like an Expander containing a TreeView of the items underneath it. You could style the top-level items to look however you like.

    The downside would be that the trees under the top-level items would be virtualized individually, not as a whole. That is, they would not share containers. Unless you have a ton of top-level items, that probably won't be a big deal.

    Example:

    <ItemsControl xmlns:s="clr-namespace:System;assembly=mscorlib"
                  ItemsSource="{Binding Types}">
      <ItemsControl.Resources>
        <ControlTemplate x:Key="ExpanderButtonTemplate" TargetType="ToggleButton">
          <Border Background="Transparent" Padding="3,2">
            <ContentPresenter />
          </Border>
        </ControlTemplate>
        <Style TargetType="Expander">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="Expander">
                <DockPanel LastChildFill="True">
                  <ToggleButton DockPanel.Dock="Top"
                                IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
                                Template="{StaticResource ExpanderButtonTemplate}">
                    <ContentPresenter ContentSource="Header" />
                  </ToggleButton>
                  <Border>
                    <ContentPresenter x:Name="contentSite" Visibility="Collapsed" />
                  </Border>
                </DockPanel>
                <ControlTemplate.Triggers>
                  <Trigger Property="IsExpanded" Value="True">
                    <Setter TargetName="contentSite" Property="Visibility" Value="Visible" />
                  </Trigger>
                </ControlTemplate.Triggers>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </ItemsControl.Resources>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Expander Header="{Binding Name}">
            <TreeView ItemsSource="{Binding SubTypes}" BorderThickness="0" Padding="0">
              <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type models:Type}"
                                          ItemsSource="{Binding SubTypes}">
                  <TextBlock Text="{Binding Name}"/>
                  <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate DataType="{x:Type models:SubType}">
                      <TextBlock Text="{Binding Name}"/>
                    </DataTemplate>
                  </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
              </TreeView.ItemTemplate>
            </TreeView>
          </Expander>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    Click on one of the top-level items to expand the tree beneath it.

    Screenshot