为什么某些 WPF 自定义样式元素被忽略而其他元素被坚持?

Why Are Some WPF Custom Style Elements Ignored Whilst Others Adhered?

我有点困惑,试图了解视觉树内部的样式覆盖是如何工作的。

我有两个示例 - 第一个,定义 DataGridCell 完美无缺,如图所示。

第二个,定义 ToggleButton,完全被忽略了,但我很难找出为什么第一个起作用,而第二个不起作用。谁能提供任何见解?

工作 - DataGridCell 风格定义于 DataGrid.Resources:

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding hello}">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridCell}"><!--DataGridCell is a child of DataGrid's Visual Tree -->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border Padding="10" Background="Red">
                          <ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.Resources>


非工作 - ToggleButton Resources 中定义的样式被忽略:

<Expander>
    <Expander.Resources>
        <Style TargetType="{x:Type ToggleButton}"><!--ToggleButton is a child of Expander's Visual Tree-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <TextBlock>Hello World!</TextBlock>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Expander.Resources>
    <Expander.Header>Header</Expander.Header>
    <Expander.Content>Body</Expander.Content>
</Expander>

一些控件为它们使用的控件定义了它们自己的 Styles。例如,Expander 的默认模板为 ToggleButton 定义了一个 ControlTemplate 并将其设置为这样(我不想在这里复制整个默认样式,因为它很长):

<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" 
    ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" 
    Content="{TemplateBinding Header}" ... Style="{StaticResource ExpanderDownHeaderStyle}" ... />

<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="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>

因为这是本地值,所以它优先于您定义为资源的样式。
正如评论中提到的 dkozl,检查 Dependency Property Setting Precedence List 找出哪个优先于什么。