WPF中Expander的用法和控件模板詳解


一、Expander的用法

  在WPF中,Expander是一個很實用的復合控件,可以很方便的實現下拉菜單和導航欄等功能。先介紹簡單的用法,而后分析他的控件模板。

<Window.Resources>
        <ResourceDictionary>
            <Style x:Key="Expander.StackPanel.Style" TargetType="FrameworkElement">
                <Setter Property="MaxWidth" Value="80"></Setter>
                <Setter Property="MinWidth" Value="50"></Setter>
                <Setter Property="HorizontalAlignment" Value="Left"></Setter>
            </Style>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        
        <Expander Style="{DynamicResource ExpanderStyle}" Header="頭部">
            <StackPanel>
                <Button Style="{StaticResource Expander.StackPanel.Style}">內容1</Button>
                <RadioButton Style="{StaticResource Expander.StackPanel.Style}">內容2</RadioButton>
                <TextBox Style="{StaticResource Expander.StackPanel.Style}">內容3</TextBox>
                <TextBlock Style="{StaticResource Expander.StackPanel.Style}">內容4</TextBlock>
            </StackPanel>
        </Expander>
    </Grid>

可以看到Expander主要分為頭部和內容兩部分,展開時才顯示內容,而內容部分可以存放豐富的內容

效果圖:

二、控件模板

  如何獲取控件本身默認的控件模板請看我的另一篇文章:https://www.cnblogs.com/xiaomengshan/p/11446436.html

  因為控件模板比較復雜,先看大概的構成:

 

再看看主樣式部分(ExpanderSytle)的構成:

 

再看向下展開時頭部的樣式構成:

 

如下為我標注了注釋的完整控件模板代碼:

<SolidColorBrush x:Key="Expander.MouseOver.Circle.Stroke" Color="#FF5593FF"/>
            <SolidColorBrush x:Key="Expander.MouseOver.Circle.Fill" Color="#FFF3F9FF"/>
            <SolidColorBrush x:Key="Expander.MouseOver.Arrow.Stroke" Color="#FF000000"/>
            <SolidColorBrush x:Key="Expander.Pressed.Circle.Stroke" Color="#FF3C77DD"/>
            <SolidColorBrush x:Key="Expander.Pressed.Circle.Fill" Color="#FFD9ECFF"/>
            <SolidColorBrush x:Key="Expander.Pressed.Arrow.Stroke" Color="#FF000000"/>
            <SolidColorBrush x:Key="Expander.Disabled.Circle.Stroke" Color="#FFBCBCBC"/>
            <SolidColorBrush x:Key="Expander.Disabled.Circle.Fill" Color="#FFE6E6E6"/>
            <SolidColorBrush x:Key="Expander.Disabled.Arrow.Stroke" Color="#FF707070"/>
            <SolidColorBrush x:Key="Expander.Static.Circle.Fill" Color="#FFFFFFFF"/>
            <SolidColorBrush x:Key="Expander.Static.Circle.Stroke" Color="#FF333333"/>
            <SolidColorBrush x:Key="Expander.Static.Arrow.Stroke" Color="#FF333333"/>
            <!--ExpandDirection=Right,即向右展開時的頭部樣式-->
            <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="Yellow" HorizontalAlignment="Center" Height="19" Stroke="Yellow" 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>
            <!--ExpandDirection=Up,即向上展開時的頭部樣式-->
            <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>
            <!--ExpandDirection=Left,即向左展開時的頭部樣式-->
            <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>
            <!--ExpandDirection=Down,即向下展開時的頭部樣式(一般默認向下展開)-->
            <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和Path組成圓圈箭頭圖標 ContentPresenter為文字)-->
                                    <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="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="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>
            <!--Expander樣式-->
            <Style x:Key="ExpanderStyle" 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>
                                <!--向左、右、上展開修改DockPanel中標題和內容布局方式實現-->
                                <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>

 

  知道了Expander默認控件模板的構成就可以根據需要修改,輕松構建自定義的導航欄等功能(建議只修改需要修改的部分)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM