11

有用的东西

我需要对作为 StackPanel 的子项的某种类型的控件进行样式设置。我正在使用:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBlock}">...</Style>
    </StackPanel.Resources>
    <TextBlock ...>
    ...
</StackPanel>

这很好用!每个 TextBlock 都会查看其父级(StackPanel)的资源,以了解应如何设置样式。将 TextBlock 嵌套在 StackPanel 下多远都没关系......如果它在其直接父级中找不到样式,它将查看其父级的父级,依此类推,直到找到某些东西(在这种情况下, 中定义的样式)。

不起作用的东西

当我将 TextBlock 嵌套在具有模板的 ContentControl 中时遇到了问题(请参见下面的代码)。ControlTemplate 似乎破坏了 TextBlock 从其父母、祖父母、...

ControlTemplate 的使用似乎有效地消除了 TextBlock 寻找其正确样式的方法(StackPanel.Resources 中的那个)。当它遇到 ControlTemplate 时,它​​会停止在树上的资源中查找其样式,而是默认为 Application 本身的 MergedDictionaries 中的样式。

<StackPanel Orientation="Vertical" Background="LightGray">
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Foreground" Value="Green" />
        </Style>
    </StackPanel.Resources>

    <TextBlock Text="plain and simple in stackpanel, green" />
    <ContentControl>
        <TextBlock Text="inside ContentControl, still green" />
    </ContentControl>
    <ContentControl>
        <ContentControl.Template>
            <ControlTemplate TargetType="{x:Type ContentControl}">
                <StackPanel Orientation="Vertical">
                    <ContentPresenter />
                    <TextBlock Text="how come this one - placed in the template - is not green?" />
                </StackPanel>
            </ControlTemplate>
        </ContentControl.Template>
        <TextBlock Text="inside ContentControl with a template, this one is green as well" />
    </ContentControl>

</StackPanel>

有没有办法——除了将 StackPanel.Resources 中的 Style 复制到 ControlTemplate.Resources 之外——让 ControlTemplate 中的 TextBlock 找到定义的样式?

谢谢...

4

1 回答 1

22

WPF 认为ControlTemplates是一个边界,并且不会x:Key在模板内应用隐式样式(没有 的样式)。

但是这个规则有一个例外:任何继承自的东西都Control将应用隐式样式。

因此,您可以使用 aLabel而不是 a TextBlock,它会应用在 XAML 层次结构中进一步定义的隐式样式,但是由于TextBlock继承自FrameworkElement而不是Control,它不会自动应用隐式样式,您必须手动添加它。

我最常见的解决方法ControlTemplate.ResourcesBasedOn在现有的隐式样式中添加一个隐式TextBlock样式

    <ControlTemplate.Resources>
        <Style TargetType="{x:Type TextBlock}" 
               BasedOn="{StaticResource {x:Type TextBlock}}" />
    <ControlTemplate.Resources>

其他常见的解决方法是:

  • 将隐式样式放在<Application.Resources>. 无论模板边界如何,此处放置的样式都将应用于您的整个应用程序。不过要小心这一点,因为它也会将样式应用于TextBlocks其他控件的内部,例如按钮或组合框

    <Application.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Foreground" Value="Green" />
        </Style>
    </Application.Resources>
    
  • 使用 aLabel而不是 aTextBlock因为它继承自Control,因此将应用在外部定义的隐式样式ControlTemplate

  • 给出基本样式 anx:Key并将其用作.TextBlock内隐式样式的基本样式ControlTemplate。它与顶级解决方案几乎相同,但是它用于具有x:Key属性的基本样式

    <Style x:Key="BaseTextBlockStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Green" />
    </Style>
    
    ...
    
    <ControlTemplate.Resources>
        <Style TargetType="{x:Type TextBlock}" 
            BasedOn="{StaticResource BaseTextBlockStyle}" />
    <ControlTemplate.Resources>
    
于 2013-01-24T14:28:31.237 回答