wpf.net-3.5control-template

WPF TreeViewItem Control Template Partially applied?


I know a ControlTemplate is suppose to replace the default one entirely and this seems to work when not using a HierarchicalDataTemplate. However using a HierarchicalDataTemplate my control template seems to be partially used - the TreeViewItem is the control I specified containing an image etc. BUT still appears as a node with the default expander to show its children - not specified in my Template (I want my children to always be shown, but thats beside the point). It looks like this:

      <TreeView>
        <TreeView.Resources>

            <Style x:Key="MyNodeStyle" TargetType="TreeViewItem">
                <Setter Property="SnapsToDevicePixels" Value="true" />
                <Setter Property="OverridesDefaultStyle" Value="true"/>
                <Setter Property="IsExpanded" Value="true"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="TreeViewItem">
                            <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
                                <Border CornerRadius="8" BorderThickness="1" Padding="2" Margin="4, 6" BorderBrush="{StaticResource itemBorderBrush}" Background="{StaticResource itemBackgroundBrush}" x:Name="border">
                                    <DockPanel LastChildFill="False">
                                        <StackPanel Orientation="Vertical" DockPanel.Dock="Top" Height="80">
                                            <TextBlock Text="{Binding Path=DisplayValue}" HorizontalAlignment="Center" FontWeight="Bold"/>
                                            <Image Source="MyNode.png" Stretch="None"/>
                                            <TextBlock Text="{Binding Path=Notes}" TextWrapping="Wrap" Width="150"/>                                                   
                                        </StackPanel>
                                    </DockPanel>
                                </Border>
                                <ItemsPresenter />
                            </StackPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" IsItemsHost="True" HorizontalAlignment="Center" />
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

            <HierarchicalDataTemplate DataType="{x:Type src:MyNode}" ItemsSource="{Binding Path=Children}" >
                <TreeViewItem Style="{StaticResource MyNodeStyle}"/>
            </HierarchicalDataTemplate>

        </TreeView.Resources>

        <!-- Arrange the root items horizontally. -->
        <TreeView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True" Orientation="Horizontal" HorizontalAlignment="Center" />
            </ItemsPanelTemplate>
        </TreeView.ItemsPanel>

    </TreeView>

For some reason only when using a HierarchicalDataTemplate the ItemsPanel and Setter does not seem to be applied and the children are presented in the default expander. How did that expander get there when I am using my own ControlTemplate!?@#$


Solution

  • I don't think you should put the TreeViewItem inside your HierarchicalDataTemplate.

    Try this:

    <HierarchicalDataTemplate DataType="{x:Type src:MyNode}" ItemsSource="{Binding Path=Children}" >
        <StackPanel Orientation="Vertical" DockPanel.Dock="Top" Height="80">
            <TextBlock Text="{Binding Path=DisplayValue}" HorizontalAlignment="Center" FontWeight="Bold"/>
            <Image Source="MyNode.png" Stretch="None"/>
            <TextBlock Text="{Binding Path=Notes}" TextWrapping="Wrap" Width="150"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    

    Now, your template becomes:

    <ControlTemplate TargetType="TreeViewItem">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
            <Border CornerRadius="8" BorderThickness="1" Padding="2" Margin="4, 6" x:Name="border">
                <DockPanel LastChildFill="False">
                    <ContentPresenter ContentSource="Header" />
                </DockPanel>
            </Border>
            <ItemsPresenter />
        </StackPanel>
    </ControlTemplate>
    

    Is that how you intended it to look?

    Edit: the original expanders are probably there because you only use your style for child items - make your style the ItemContainerStyle for the treeview:

    <Window.Resources>
        <Style x:Key="MyNodeStyle" TargetType="TreeViewItem">
            ....
    
    <TreeView ItemContainerStyle="{StaticResource MyNodeStyle}">