具有多个按钮的 WPF 扩展器

WPF Expander with Multiple Buttons

我需要包含将在 WPF 中的扩展器上触发逻辑的按钮。我在下面附上了一张图片。

我不确定如何在 WPF 中完成此操作,或者是否可能。按钮需要连接到后端功能才能创建 objects。每个都是一个扩展器,并且应该在扩展器 header 的右侧有这些按钮,无论它们是否展开。单击时,按钮应在后面的代码中调用 _Click 方法。

这可以用扩展器完成吗?我该如何完成?

我建议您制作一个特定的 class 来为您完成这项工作,这里有一个原始框架和解释。

在顶部有一种 bread-crumb 栏,这是实际的按钮,按下时会展开目标部分。

ExpanderGroupclass,负责渲染和一些UI逻辑

有 2 个 collection,一个用于 bread-crumb 栏的 header,另一个用于 Expander 本身。

public partial class ExpanderGroup : UserControl
{
    public static readonly DependencyProperty ChildrenProperty = DependencyProperty.Register(
        "Children", typeof (ObservableCollection<Expander>), typeof (ExpanderGroup),
        new PropertyMetadata(default(ObservableCollection<Expander>)));

    public static readonly DependencyProperty ChildrenHeadersProperty = DependencyProperty.Register(
        "ChildrenHeaders", typeof (ObservableCollection<string>), typeof (ExpanderGroup),
        new PropertyMetadata(default(ObservableCollection<string>)));

    public ExpanderGroup()
    {
        InitializeComponent();
        Children = new ObservableCollection<Expander>();
        ChildrenHeaders = new ObservableCollection<string>();
    }

    public ObservableCollection<Expander> Children
    {
        get { return (ObservableCollection<Expander>) GetValue(ChildrenProperty); }
        set { SetValue(ChildrenProperty, value); }
    }

    public ObservableCollection<string> ChildrenHeaders
    {
        get { return (ObservableCollection<string>) GetValue(ChildrenHeadersProperty); }
        set { SetValue(ChildrenHeadersProperty, value); }
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        // find the corresponding expander to toggle button clicked
        // it is very primitive as it expects an exact mapping by name
        var button = (ToggleButton) sender;
        var text = (string) button.Content;
        var expander = Children.Single(s => (string) s.Header == text);

        // toggle expansion status
        expander.IsExpanded = button.IsChecked != null && (bool) button.IsChecked;

        // little helper that expands the root expander
        // (though its template should be changed for better UX)
        RootExpander.IsExpanded = Children.Any(s => s.IsExpanded);
    }
}

备注:

  • 我使用了一个非常简单的逻辑,即我根据其 header 检索相应的 Expander,您可以通过引用其索引或任何其他方式进一步增强它。
  • 还有第二个 collection ChildrenHeaders,因为如果您尝试从 2 个来源获取扩展器,它们将只出现在其中一个容器上,因为 UIElement只能有一个 parent.
  • 您可能还想设计一种机制,以便在直接操作 Expander 时,是否切换面包屑中的相应按钮。提示 :一个好的地方是 ChildrenPropertyChangedCallback,您可以在其中在切换按钮和目标 Expander
  • 之间建立更具启发性的关系

ExpanderGroup XAML部分

<UserControl x:Class="delme.ExpanderGroup"
             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:local="clr-namespace:delme"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             x:Name="Root"
             d:DesignHeight="300"
             d:DesignWidth="300"
             mc:Ignorable="d">
    <Grid>
        <StackPanel>

            <ItemsControl Background="LightBlue" ItemsSource="{Binding ElementName=Root, Path=ChildrenHeaders}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel IsItemsHost="True" Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="system:String">
                        <ToggleButton Width="75"
                                      Height="22"
                                      Margin="2"
                                      Click="ButtonBase_OnClick"
                                      Content="{Binding}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <Expander x:Name="RootExpander">
                <ItemsControl Background="LightCyan" ItemsSource="{Binding ElementName=Root, Path=Children}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel IsItemsHost="True" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </Expander>

        </StackPanel>
    </Grid>
</UserControl>

这里没有什么特别的,只是为了示例而将其保持在最低限度。您可能会稍微调整一下,尤其是 re-defining RootExpander 的模板,因为 IMO 应该简单地隐藏小箭头以获得更好的用户体验。您 can/should 使用 Blend 可以非常轻松地调整其模板。

用法示例

<Window x:Class="delme.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:local="clr-namespace:delme"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow"
        Width="525"
        Height="350"
        mc:Ignorable="d">
    <Grid>

        <local:ExpanderGroup>
            <local:ExpanderGroup.ChildrenHeaders>
                <system:String>Expander1</system:String>
                <system:String>Expander2</system:String>
            </local:ExpanderGroup.ChildrenHeaders>
            <local:ExpanderGroup.Children>
                <Expander Header="Expander1">
                    <TextBlock Text="abcd" />
                </Expander>
                <Expander Header="Expander2">
                    <TextBlock Text="efgh" />
                </Expander>
            </local:ExpanderGroup.Children>
        </local:ExpanderGroup>

    </Grid>
</Window>

继续改进该设计!

要使您的 Button 出现在最右边,您必须使用 DockPanel 作为您的 Expander.HeaderTemplate。但是 Expander 在显示扩展圆圈的顶部使用 ToggleButton。此 ToggleButtonHorizontalAlignment 设置为左​​。因此,我们需要将 Style 中的此设置更改为 ExpanderDownHeaderStyle 键为

<ContentPresenter Grid.Column="1" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" ... />

按原样复制粘贴下面的 XAML。

<Window.Resources>
        <SolidColorBrush x:Key="Expander.MouseOver.Circle.Stroke" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Expander.MouseOver.Circle.Fill" Color="Transparent"/>
        <SolidColorBrush x:Key="Expander.MouseOver.Arrow.Stroke" Color="#222"/>
        <SolidColorBrush x:Key="Expander.Pressed.Circle.Stroke" Color="#FF526C7B"/>
        <SolidColorBrush x:Key="Expander.Pressed.Circle.Fill" Color="Transparent"/>
        <SolidColorBrush x:Key="Expander.Pressed.Arrow.Stroke" Color="#FF003366"/>
        <SolidColorBrush x:Key="Expander.Disabled.Circle.Stroke" Color="DarkGray"/>
        <SolidColorBrush x:Key="Expander.Disabled.Circle.Fill" Color="Transparent"/>
        <SolidColorBrush x:Key="Expander.Disabled.Arrow.Stroke" Color="#666"/>
        <SolidColorBrush x:Key="Expander.Static.Circle.Fill" Color="Transparent"/>
        <SolidColorBrush x:Key="Expander.Static.Circle.Stroke" Color="DarkGray"/>
        <SolidColorBrush x:Key="Expander.Static.Arrow.Stroke" Color="#666"/>
        <Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border Padding="{TemplateBinding Padding}">
                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="19"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Grid>
                                    <Grid.LayoutTransform>
                                        <TransformGroup>
                                            <TransformGroup.Children>
                                                <TransformCollection>
                                                    <RotateTransform Angle="-90"/>
                                                </TransformCollection>
                                            </TransformGroup.Children>
                                        </TransformGroup>
                                    </Grid.LayoutTransform>
                                    <Ellipse x:Name="circle" Fill="{StaticResource Expander.Static.Circle.Fill}" HorizontalAlignment="Center" Height="19" Stroke="{StaticResource Expander.Static.Circle.Stroke}" VerticalAlignment="Center" Width="19"/>
                                    <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="{StaticResource Expander.Static.Arrow.Stroke}" StrokeThickness="2" VerticalAlignment="Center"/>
                                </Grid>
                                <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.MouseOver.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Stroke}"/>
                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Pressed.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Disabled.Arrow.Stroke}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border Padding="{TemplateBinding Padding}">
                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="19"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Grid>
                                    <Grid.LayoutTransform>
                                        <TransformGroup>
                                            <TransformGroup.Children>
                                                <TransformCollection>
                                                    <RotateTransform Angle="180"/>
                                                </TransformCollection>
                                            </TransformGroup.Children>
                                        </TransformGroup>
                                    </Grid.LayoutTransform>
                                    <Ellipse x:Name="circle" Fill="{StaticResource Expander.Static.Circle.Fill}" HorizontalAlignment="Center" Height="19" Stroke="{StaticResource Expander.Static.Circle.Stroke}" VerticalAlignment="Center" Width="19"/>
                                    <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="{StaticResource Expander.Static.Arrow.Stroke}" StrokeThickness="2" VerticalAlignment="Center"/>
                                </Grid>
                                <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.MouseOver.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Stroke}"/>
                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Pressed.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Disabled.Arrow.Stroke}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border Padding="{TemplateBinding Padding}">
                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="19"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Grid>
                                    <Grid.LayoutTransform>
                                        <TransformGroup>
                                            <TransformGroup.Children>
                                                <TransformCollection>
                                                    <RotateTransform Angle="90"/>
                                                </TransformCollection>
                                            </TransformGroup.Children>
                                        </TransformGroup>
                                    </Grid.LayoutTransform>
                                    <Ellipse x:Name="circle" Fill="{StaticResource Expander.Static.Circle.Fill}" HorizontalAlignment="Center" Height="19" Stroke="{StaticResource Expander.Static.Circle.Stroke}" VerticalAlignment="Center" Width="19"/>
                                    <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="{StaticResource Expander.Static.Arrow.Stroke}" StrokeThickness="2" VerticalAlignment="Center"/>
                                </Grid>
                                <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.MouseOver.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Stroke}"/>
                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Pressed.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Disabled.Arrow.Stroke}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderHeaderFocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border>
                            <Rectangle Margin="0" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border Padding="{TemplateBinding Padding}">
                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="19"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Ellipse x:Name="circle" Fill="{StaticResource Expander.Static.Circle.Fill}" HorizontalAlignment="Center" Height="19" Stroke="{StaticResource Expander.Static.Circle.Stroke}" VerticalAlignment="Center" Width="19"/>
                                <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="{StaticResource Expander.Static.Arrow.Stroke}" StrokeThickness="2" VerticalAlignment="Center"/>
                                <ContentPresenter Grid.Column="1" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.MouseOver.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Stroke}"/>
                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Pressed.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Disabled.Arrow.Stroke}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderStyle1" TargetType="{x:Type Expander}">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
                            <DockPanel>
                                <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                <ContentPresenter x:Name="ExpandSite" DockPanel.Dock="Bottom" Focusable="false" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </DockPanel>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="true">
                                <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
                            </Trigger>
                            <Trigger Property="ExpandDirection" Value="Right">
                                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                                <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
                            </Trigger>
                            <Trigger Property="ExpandDirection" Value="Up">
                                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                                <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
                            </Trigger>
                            <Trigger Property="ExpandDirection" Value="Left">
                                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                                <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>    

扩展器使用

<Expander Grid.Row="1" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Style="{DynamicResource ExpanderStyle1}">            
    <Expander.HeaderTemplate>
        <DataTemplate>
            <DockPanel LastChildFill="False" Background="LimeGreen">
                <TextBlock Text="Expander1"/>
                <Button Content="Press" DockPanel.Dock="Right"/>
                <Button Content="Press" DockPanel.Dock="Right"/>
            </DockPanel>
        </DataTemplate>
    </Expander.HeaderTemplate>
    <StackPanel Background="LightSteelBlue"></StackPanel>
</Expander>

输出: