WPF ControlTemplate中断样式 [英] WPF ControlTemplate breaks style

查看:110
本文介绍了WPF ControlTemplate中断样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

起作用的东西

我需要设置某些类型的控件的样式,这些控件是StackPanel的子级.我正在使用:

I need to style controls of a certain type that are children of a StackPanel. I'm using:

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

这很好用!每个TextBlock都会查找其父级(StackPanel)的资源,以了解其样式.紧紧将TextBlock嵌套到StackPanel的下方无所谓...如果在其直接父级中找不到样式,它将查看其父级的父级,依此类推,直到找到某项为止(在这种情况下) ,是)中定义的样式.

And this works fine! Each TextBlock looks to the resources of it's parent (the StackPanel) to find out how it should be styled. It doesn't matter how far down you nest the TextBlock down a StackPanel... if it doesn't find a style in its direct parent, it will look at its parent's parent and so on, until it finds something (in this case, the style that was defined in ).

无效的内容

当我将TextBlock嵌套在具有模板的ContentControl中时,我遇到了一个问题(请参见下面的代码). ControlTemplate似乎破坏了TextBlock从其父母,祖父母等处获取其样式的方式.

I ran into a problem when I nested a TextBlock inside a ContentControl, which had a Template (see code below). The ControlTemplate seems to disrupt the way a TextBlock retrieves its style from its parents, grandparents,...

使用ControlTemplate似乎可以有效地消除TextBlock查找其正当样式(StackPanel.Resources中的样式)的手段.当遇到ControlTemplate时,它将停止在树上的资源中寻找其样式,而是默认为应用程序本身的MergedDictionaries中的样式.

The use of a ControlTemplate effectively seems to knock out cold the TextBlock's means of finding its rightful style (the one in StackPanel.Resources). When it encounters a ControlTemplate, it stops looking for its style in the resources up the tree, and instead defaults to the style in MergedDictionaries of the Application itself.

<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中的样式复制到ControlTemplate.Resources之外,还有什么方法可以使ControlTemplate中的TextBlock查找定义的样式吗?

Is there a way - besides duplicating the Style in StackPanel.Resources to ControlTemplate.Resources - to make the TextBlock inside that ControlTemplate find the defined style?

谢谢...

推荐答案

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

WPF considers ControlTemplates to be a boundry, and will not apply implicit styles (styles without an x:Key) inside of templates.

但是此规则有一个例外:从Control继承的任何内容都将应用隐式样式.

But there is one exception to this rule: anything that inherits from Control will apply implicit styles.

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

So you could use a Label instead of a TextBlock, and it would apply the implicit style defined further up your XAML hierarchy, however since TextBlock inherits from FrameworkElement instead of Control, it won't apply the implicit style automatically and you have to add it manually.

我最常见的解决方法是在ControlTemplate.Resources中添加隐式样式,即BasedOn现有的隐式TextBlock样式

My most common way to get around this is to add an implicit style in the ControlTemplate.Resources that is BasedOn the existing implicit TextBlock style

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

其他解决此问题的常用方法是:

Other common ways of getting around this are:

  • 将隐式样式放置在<Application.Resources>中.此处放置的样式将适用于整个应用程序,而不管模板的边界如何.不过请注意这一点,因为它将样式也应用到其他控件内的TextBlocks,例如Buttons或ComboBoxes

  • Place the implicit style in <Application.Resources>. Styles placed here will apply to your entire application, regardless of template boundaries. Be careful with this though, as it will apply the style to TextBlocks inside of other controls as well, like Buttons or ComboBoxes

<Application.Resources>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Green" />
    </Style>
</Application.Resources>

  • 使用Label代替TextBlock,因为它是从Control继承的,因此将应用在ControlTemplate

  • Use a Label instead of a TextBlock since it's inherited from Control, so will apply implicit Styles defined outside the ControlTemplate

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

    Give the base style an x:Key and use it as the base style for an implicit TextBlock styles inside the ControlTemplate. It's pretty much the same as the top solution, however it's used for base styles that have an x:Key attribute

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

  • 这篇关于WPF ControlTemplate中断样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆