Search code examples
wpfsilverlightxamlexpander

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.


Solution

  • 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.