Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Expander Button Styled so it is inside Expander Header

I am using the Expander control and have styled the header as shown in the picture below:

http://www.hughgrice.com/Expander.jpg

The problem I have is that I want the expander button to be contained within the header so that the line for the end of the header template aligns with the Expander content i.e. I ultimatly want to end up with something similar to the image below:

http://www.hughgrice.com/Expander.gif

Thanks in advance.

like image 711
Burt Avatar asked May 22 '10 21:05

Burt


2 Answers

I see that you want to actually move the expander button into your HeaderTemplate, not just restyle it. This is easily done with FindAncestor:

First add a ToggleButton and bind its IsChecked property using FindAncestor, along these lines:

<DataTemplate x:Key="MyHeaderTemplate">
  <Border ...>
    <DockPanel>
      <!-- Expander button -->
      <ToggleButton
         IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor,Header,1}}"
         Content=... />

      <!-- Other content here -->
      ...
    </DockPanel>
  </Border>
</DataTemplate>           

This adds an expand button inside the header template but does not hide the original button provided by the Expander. To do this I recommend you replace the Expander's ControlTemplate.

Here is a complete copy of Expander's ControlTemplate with the ToggleButton replaced with a simple ContentPresenter:

<ControlTemplate x:Key="ExpanderWithoutButton" TargetType="{x:Type Expander}">
  <Border BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          Background="{TemplateBinding Background}"
          CornerRadius="3"
          SnapsToDevicePixels="true">
    <DockPanel>
      <ContentPresenter
        Content="{TemplateBinding Header}"
        ContentTemplate="{TemplateBinding HeaderTemplate}"
        ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
        DockPanel.Dock="Top"
        Margin="1"
        Focusable="false" />
      <ContentPresenter
        x:Name="ExpandSite"
        Visibility="Collapsed"
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="{TemplateBinding Padding}"
        Focusable="false" />
    </DockPanel>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsExpanded" Value="true">
      <Setter Property="Visibility" Value="Visible" TargetName="ExpandSite"/>
    </Trigger>
    <Trigger Property="IsEnabled" Value="false">
      <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

It might be used as follows:

<Expander Template="{StaticResource ExpanderWithoutButton}">

  <Expander.HeaderTemplate>
    <DataTemplate ...>
      <Border ...>
        <DockPanel>
          <ToggleButton ...
            IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor,Header,1}}" />
          ... other header template content here ...

A simpler alternative would be to just set a negative margin in yourHeaderTemplate to cover the expander button. Instead of the ControlTemplate shown above, your DataTemplat would just contain something like this:

<DataTemplate ...>
  <Border Margin="-20 0 0 0" ... />

Adjust the negative margin to get the look you want. This solution is simpler but inferior in that if you switch to a different system theme the required margin may change and your expander may no longer look good.

like image 162
Ray Burns Avatar answered Oct 07 '22 00:10

Ray Burns


You will need to edit the Expander's Template, not the HeaderTemplate. The HeaderTemplate doesn't contain the expand button, just the content inside of it.

The default control template looks something like this:

<ControlTemplate TargetType="{x:Type Expander}">
    <Border>
        <DockPanel>
            <ToggleButton x:Name="HeaderSite"
                          ContentTemplate="{TemplateBinding HeaderTemplate}"
                          Content="{TemplateBinding Header}"
                          DockPanel.Dock="Top"
                          IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />
            <ContentPresenter x:Name="ExpandSite" />
        </DockPanel>
    </Border>
</ControlTemplate>

I took out most of the attributes but left in the important stuff. Basically, you will want to add your customizations around the ToggleButton. That is what contains the expand button and the header content.

If you have Expression Blend, it makes this process much easier because you can simply edit a copy of the original template. Visual Studio doesn't really have this ability yet.

like image 40
Josh Avatar answered Oct 07 '22 00:10

Josh