wpf - 为什么某些 WPF 自定义样式元素被忽略,而其他元素却被保留?

标签 wpf xaml wpf-style

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

我有两个示例 - 第一个示例定义 DataGridCell 效果很好,如图所示。

第二个定义 ToggleButton 被完全忽略,但我很难找出为什么第一个有效,但第二个无效。谁能提供任何见解?

工作 - DataGridCellDataGrid.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>

working


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

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

enter image description here

最佳答案

某些控件为其使用的控件定义了自己的样式。例如 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找出哪个优先于哪个。

关于wpf - 为什么某些 WPF 自定义样式元素被忽略,而其他元素却被保留?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33221268/

相关文章:

WPF ListBox 失去焦点后将焦点设置为第一项

c# - 如何在wpf控件构造函数中传递参数?

XAML 2009 和 .NET 4.6/Windows 10

xaml - 如何在 XAML 中调用 ResourceDictionary 文件中的样式?

wpf - Shift+Tab 在样式化 WPF 组合框中不起作用

c# - Application.run(Windows) 与 Application.run()

wpf - 托管 WPF 和 native 代码互操作。 WPF 托管在 ServicedComponent 中

c# - WindowLoaded() 没有被调用

c# - 依赖属性更改时 StackPanel 可见性未更新

c# - 自定义样式的 TextBox SelectionStart 始终为 0