Search code examples
c#wpfmvvmdata-bindingtreeview

How to change the position of Expand / Collapse button in Tree View in WPF?


I have a tree view in WPF in C# with parent and child nodes. I want to bring the Expand/Collapse button to the right side. I tried the flow direction property but it is not working as expected. How to change the position of the Expand/Collapse button in tree view?


Solution

  • Your best approch if you override the Treeview Control Template. Here is an example:

      <Window.Resources>
        <Color x:Key="SelectedBackgroundColor">#FFC5CBF9</Color>
        <Color x:Key="SelectedUnfocusedColor">#FFDDDDDD</Color>
    
        <Color x:Key="GlyphColor">#FF444444</Color>
        <Color x:Key="GlyphMouseOver">sc#1, 0.004391443, 0.002428215, 0.242281124</Color>
    
        <Style x:Key="{x:Type TreeView}"
       TargetType="TreeView">
            <Setter Property="OverridesDefaultStyle"
          Value="True" />
            <Setter Property="SnapsToDevicePixels"
          Value="True" />
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
          Value="Auto" />
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
          Value="Auto" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TreeView">
                        <Border Name="Border"
                CornerRadius="1"
                BorderThickness="1">
                            <Border.BorderBrush>
                                <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
                            </Border.BorderBrush>
                            <Border.Background>
                                <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
                            </Border.Background>
                            <ScrollViewer Focusable="False"
                        CanContentScroll="False"
                        Padding="4">
                                <ItemsPresenter />
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    
        <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">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CheckStates">
                                    <VisualState x:Name="Checked">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="Collapsed">
                                                <DiscreteObjectKeyFrame KeyTime="0"
                                            Value="{x:Static Visibility.Hidden}" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="Expanded">
                                                <DiscreteObjectKeyFrame KeyTime="0"
                                            Value="{x:Static Visibility.Visible}" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unchecked" />
                                    <VisualState x:Name="Indeterminate" />
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Path x:Name="Collapsed"
                                  HorizontalAlignment="Left"
                                  VerticalAlignment="Center"
                                  Margin="1,1,1,1"
                                  Data="M 4 0 L 8 4 L 4 8 Z">
                                <Path.Fill>
                                    <SolidColorBrush Color="{DynamicResource GlyphColor}" />
                                </Path.Fill>
                            </Path>
                            <Path x:Name="Expanded"
                                  HorizontalAlignment="Left"
                                  VerticalAlignment="Center"
                                  Margin="1,1,1,1"
                                  Data="M 0 4 L 8 4 L 4 8 Z"
                                  Visibility="Hidden">
                                <Path.Fill>
                                    <SolidColorBrush Color="{DynamicResource GlyphColor}" />
                                </Path.Fill>
                            </Path>
                        </Grid>
                    </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 Width="Auto" />
                                <ColumnDefinition MinWidth="19" Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="SelectionStates">
                                    <VisualState x:Name="Selected">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Bd"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)"
                                                >
                                                <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedBackgroundColor}" />
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unselected" />
                                    <VisualState x:Name="SelectedInactive">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Bd"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                                                <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedUnfocusedColor}" />
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="ExpansionStates">
                                    <VisualState x:Name="Expanded">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="ItemsHost">
                                                <DiscreteObjectKeyFrame KeyTime="0"
                                            Value="{x:Static Visibility.Visible}" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Collapsed" />
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}"
                                          ClickMode="Press"
                                          Grid.Column="1"
                                          IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <Border x:Name="Bd"
                                    Grid.Column="0"
                                    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="0"
                                            Grid.ColumnSpan="2"
                                            Visibility="Collapsed" />
                        </Grid>
                        <ControlTemplate.Triggers>
                            <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>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        
    </Window.Resources>
    <Grid>
        <TreeView>
            <TreeViewItem Header="Cold Drinks">
                <TreeViewItem Header="Coke"></TreeViewItem>
                <TreeViewItem Header="Pepsi"></TreeViewItem>
                <TreeViewItem Header="Orange Juice"></TreeViewItem>
                <TreeViewItem Header="Milk"></TreeViewItem>
                <TreeViewItem Header="Iced Tea"></TreeViewItem>
                <TreeViewItem Header="Mango Shake"></TreeViewItem>
            </TreeViewItem>
        </TreeView>
    </Grid>
    

    Here is the result:image