2
votes

Background

I've searched fot a day now, without a good result. What I basically try to achieve is the following treeview:

<Grid>
    <TreeView>
        <TreeViewItem>
            <TreeViewItem.Header>
                <StackPanel>
                    <TextBlock Text="Header Content 1"/>
                    <TextBlock Text="Header Content 2"/>
                </StackPanel>
            </TreeViewItem.Header>
            <StackPanel >
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
            </StackPanel>
        </TreeViewItem>
        <TreeViewItem>
            <TreeViewItem.Header>
                <StackPanel>
                    <TextBlock Text="Content Footer"/>
                    <TextBlock Text="Content Footer"/>
                </StackPanel>
            </TreeViewItem.Header>
        </TreeViewItem>
    </TreeView>
</Grid>

The Itemspresenter of the treeview should present its content between two content panels (Header & Footer), except that in the code above requires two treeview items and I would like to have it as 1 (selectable) treeview item..

If edited the default Controltemplate of the treeview in an attempt to add a textblock on a third row in a Grid, but for some reason it copies this textblock twice when the treeview item is expanded:

<Window.Resources>
    <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ToggleButton">
                    <Grid Width="15"
                          Height="13"
                          Background="Transparent">
                    <Path x:Name="ExpandPath"
                            HorizontalAlignment="Left" 
                            VerticalAlignment="Center" 
                            Margin="1,1,1,1"
                            Fill="{StaticResource GlyphBrush}"
                            Data="M 4 0 L 8 4 L 4 8 Z"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="TreeViewItemFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border>
                        <Rectangle  Margin="0,0,0,0"
                                    StrokeThickness="5"
                                    Stroke="Black"
                                    StrokeDashArray="1 2"
                                    Opacity="0"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Padding" Value="1,0,0,0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition MinWidth="19" Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <ToggleButton x:Name="Expander"
                          Style="{StaticResource ExpandCollapseToggleStyle}"
                          IsChecked="{Binding Path=IsExpanded,
                          RelativeSource={RelativeSource TemplatedParent}}"
                          ClickMode="Press"/>
                        <Border   Name="Bd"
                                  Grid.Column="1"
                                  Background="{TemplateBinding Background}"
                                  BorderBrush="{TemplateBinding BorderBrush}"
                                  BorderThickness="{TemplateBinding BorderThickness}"
                                  Padding="{TemplateBinding Padding}">
                            <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost"
                                          Grid.Row="1"
                                          Grid.Column="1"
                                          Grid.ColumnSpan="2"/>
                        <TextBlock Grid.Row="2" Grid.Column="1" Text="Footer Text"></TextBlock>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter TargetName="ItemsHost"
                                    Property="Visibility"
                                    Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="HasItems" Value="false">
                            <Setter TargetName="Expander"
                                    Property="Visibility"
                                    Value="Hidden"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HasHeader" Value="false"/>
                                <Condition Property="Width" Value="Auto"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HasHeader" Value="false"/>
                                <Condition Property="Height" Value="Auto"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
                        </MultiTrigger>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>                            </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <TreeView>
        <TreeViewItem>
            <TreeViewItem.Header>
                <StackPanel>
                    <TextBlock Text="Treeview Item 1"/>
                    <TextBlock Text="Header Content"/>
                </StackPanel>
            </TreeViewItem.Header>
            <StackPanel >
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
            </StackPanel>
        </TreeViewItem>
        <TreeViewItem>
            <TreeViewItem.Header>
                <StackPanel>
                    <TextBlock Text="Treeview Item 2"/>
                    <TextBlock Text="Header Content"/>
                </StackPanel>
            </TreeViewItem.Header>
            <StackPanel >
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
                <TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
            </StackPanel>
        </TreeViewItem>
    </TreeView>
</Grid>

In the example above the Footer Content is shown twice because it is added to the bottom of the Itemspresenter.

Question

Does anyone know how to solve this? Or perhaps knows a different approach to achieve the same result?

1
I'm having trouble understanding what you're trying to accomplish. Do you want a header and footer that each appear exactly once -- before and after the items, respectively? Or does each item have a header and footer? - Michael Gunter
The answer of viv solves my question. Each treeview item has a header and a footer with an expandable item (itemsprsenter in this case). Both the header and footer should always be visible, but expander should expand inbetween. With my code, the footer text was wrapped again in the treeviewitem, thus showing twice implicitly.. the rest follow's from Viv's solution. - Miquillo

1 Answers

1
votes

The problem here is the Content of the TreeViewItem gets wrapped in an implicit TreeViewItem by itself which thus gets another "footer" thus making it look like 2 "footer" elements per TreeViewItem.

Confirmed with Snoop:

The TreeViewItem we actually add

enter image description here

and the implicit one created by the Content of TreeViewItem

enter image description here

Work-around:

just apply a name to the "footer" TextBlock such as

<TextBlock x:Name="footer"
            Grid.Row="2"
            Grid.Column="1"
            Text="Footer Text" />

and update the Trigger for HasItems -> False to:

<Trigger Property="HasItems"
          Value="false">
  <Setter TargetName="Expander"
          Property="Visibility"
          Value="Hidden" />
  <Setter TargetName="footer"
          Property="Visibility"
          Value="Collapsed" />
</Trigger>

Now the footer text will only be visible when the TreeViewItem has children thereby giving you the appearance your expecting