peterc
peterc

Reputation: 7863

How to style the actual header parts, and not just the content, of an expander

I have a WPF items control where I want to group items using an expander.

I have the following markup...

        <Window x:Class="ItemsControlGrouped.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:ItemsControlGrouped"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
      <Window.Resources>
        <Style x:Key="ContainerStyle" TargetType="{x:Type GroupItem}">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate>
                <Expander IsExpanded="True" HorizontalAlignment="Stretch">
                  <Expander.Header>
                    
                    <StackPanel Orientation="Horizontal" Background="LightGray" HorizontalAlignment="Stretch">
                      <TextBlock Text="{Binding Name}"  />
                      <TextBlock Margin="5,0,0,0" Text="{Binding ItemCount}" />
                      <TextBlock Text=" item(s)"  />
                    </StackPanel>
                    
                  </Expander.Header>
                  <ItemsPresenter />
                  </Expander>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </Window.Resources>
      <ItemsControl Name="list">
        <ItemsControl.GroupStyle>
          <GroupStyle ContainerStyle="{StaticResource ContainerStyle}"/>
        </ItemsControl.GroupStyle>
        <ItemsControl.ItemTemplate>
          <DataTemplate>
            <Border Margin="5" Padding="0" BorderThickness="1"  Background="LightBlue" CornerRadius="4">
              <TextBlock Padding="5" Text="{Binding Name}"/>
            </Border>
          </DataTemplate>
        </ItemsControl.ItemTemplate>

        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"></WrapPanel>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
      </ItemsControl>
    </Window>

I wish to style the expander panel, for example I would like the whole expander row to have a background colour, and maybe some padding etc.

Looking in the Visual Explorer, this all seems to be in an area HeaderSite, as we can see below...

enter image description here

So, the area in the red highlight, I would like to add a background too (not just the text box as can I have done in the template).

Is there any way of doing this?

Upvotes: 1

Views: 214

Answers (1)

Stewbob
Stewbob

Reputation: 16899

Yes, you are correct. To style that part of the Expander, you need to get pretty deep into the ControlTemplate. Shown below is a basic example similar to a custom style of the ToggleButton and Expander that I've been using for several years.

    <Style x:Key="ExpanderToggleButton"
             TargetType="{x:Type ToggleButton}">
        <Setter Property="UseLayoutRounding"
                    Value="True"/>
        <Setter Property="SnapsToDevicePixels"
                    Value="True"/>
        <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Grid Height="24" Width="24">
                            <Border x:Name="border"
                                            CornerRadius="12"
                                            Background="Black"/>
                            <Path x:Name="arrow" Fill="White"
                                        Data="M4.5 9 l4 0 l3.5 4.6667 l3.5 -4.6667 l4 0 l-7.5 10 z"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver"
                                             Value="True">
                                <Setter TargetName="border"
                                                Property="Background"
                                                Value="DarkGray"/>
                                <Setter TargetName="arrow"
                                                Property="Fill"
                                                Value="LightGray"/>
                            </Trigger>
                            <Trigger Property="IsChecked"
                                             Value="True">
                                <Setter TargetName="border"
                                                Property="Background"
                                                Value="White"/>
                                <Setter TargetName="arrow"
                                                Property="Fill"
                                                Value="Black"/>
                                <Setter TargetName="arrow"
                                                Property="Data"
                                                Value="M4.5 15 l4 0 l3.5 -4.6667 l3.5 4.6667 l4 0 l-7.5 -10 z"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
    </Style>

    <Style TargetType="{x:Type Expander}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Expander}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition x:Name="ContentRow" Height="0" />
                        </Grid.RowDefinitions>
                        <Border x:Name="Border"
                                    Grid.Row="0"
                                    BorderThickness="0"
                                    CornerRadius="2,2,0,0"
                                    Background="White">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="25" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <ToggleButton Grid.Column="0" OverridesDefaultStyle="True"
                                                Style="{StaticResource ExpanderToggleButton}"
                                                IsChecked="{Binding IsExpanded, Mode=TwoWay,
                                RelativeSource={RelativeSource TemplatedParent}}">

                                </ToggleButton>
                                <!--This is the border that puts the styling around the Expander Header-->
                                <!--Add more detail here for a fancier header.-->
                                <Border Grid.Column="1" Background="DarkRed">
                                    <ContentPresenter Margin="4" 
                                            ContentSource="Header"
                                            TextBlock.Foreground="White"
                                            RecognizesAccessKey="True"/>
                                </Border>

                            </Grid>
                        </Border>
                        <Border x:Name="Content"
                                    Grid.Row="1"
                                    BorderThickness="0"
                                    CornerRadius="0,0,2,2">
                            <ContentPresenter Margin="4" />
                        </Border>
                    </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded"
                                     Value="True">
                                <Setter TargetName="ContentRow"
                                        Property="Height"
                                        Value="{Binding DesiredSize, ElementName=Content}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

enter image description here

The style I use has the toggle button almost as a separate entity from the 'header' text and background, but it's pretty easy to extend the background of the header underneath the toggle button if you're going for that look too. Once you're this deep into the ControlTemplate, you pretty much have full control over how everything looks.

Upvotes: 1

Related Questions