如何设置覆盖 WPF 中全局样式的特定控制元素设置? [英] How to set specific control element settings that override a global style in WPF?

查看:34
本文介绍了如何设置覆盖 WPF 中全局样式的特定控制元素设置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已通过应用程序范围的资源字典为应用程序中的按钮定义了全局样式.样式如下(来自另一个 SO 示例):

I have defined a global style for Buttons in my application via an application-wide Resource Dictionary. The style looks like this (followed from another SO Example):

<Style TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{DynamicResource BaseButtonBG}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid Background="{TemplateBinding Background}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>
<Style.Triggers>
    <!-- Triggers here -->>
</Style.Triggers>

它有效.但是我需要直接为我的一些按钮分配特定的值,比如边距和填充来对齐它们.我还希望能够从单个按钮的样式中覆盖颜色属性.

It works. But I need to assign specific values directly to some of my buttons, like margin and padding to align them. I also would like to have the ability to override the color properties from the style in individual buttons.

似乎我直接在特定按钮上设置的任何属性都被完全忽略了,并且只使用了全局样式中的属性.我该如何克服?

It appears that any properties I set directly on specific buttons get completely ignored and only the properties from the global style are used. How do I overcome this?

更新:澄清我想要的:在 HTML/CSS 世界(比污垢更古老)中,您可以向元素添加样式类,但您也可以将属性直接分配给覆盖类值的元素.这就是我想在 WPF 中实现的目标.

UPDATE: To clarify what I want: In the HTML/CSS world (which is older than dirt), you can add a style class to an element, but you can also assign properties directly to the element that override the class values. That's what I want to accomplish in WPF.

更新 2人们可能认为这个问题很愚蠢,因为解决方案应该是显而易见的.但是,根据我的个人测试,Padding 似乎存在一个错误,除非您将其专门绑定到控件模板中,否则根本不会更改.这种行为似乎因财产而异.由于我最初尝试覆盖一个专门涉及 Padding 的属性但没有成功,因此我必须构建此解决方法.

UPDATE 2 It's possible people think this question is stupid because the solution should be obvious. However, from my personal testing, there appears to be a bug with Padding not changing at all unless you specifically bind it in a control template. This behavior seems to change from property to property. Since my original attempt to override a property specifically involved Padding and it didn't work, I had to build this workaround.

推荐答案

YES:这是完全可行的,您可以直接在元素上分配覆盖属性,而无需执行许多人正在使用的丑陋过程来创建一个仅针对相关特定元素的特殊一次性字典条目.

YES: It's completely doable, You can assign overriding properties directly on an element without doing the ugly process many are using of creating a special one-off dictionary entry just for the specific element in question.

我不知道它是否是由 WPF 中的错误引起的,但有一个初始要求...

I don't know if its caused by a bug in WPF, but there's an initial requirement...

您的字典引用的基本样式可能需要包含您想要覆盖的任何属性.出于某种原因,不同的属性似乎表现出不同的行为.但至少在 Padding 的情况下,如果您不在 ControlTemplate TemplateBinding 中包含 Padding,您将无法在您的元素上覆盖它.

Your dictionary-referenced base style might need to include any properties that you want to be overridable. For some reason different properties seem to exhibit different behavior. But at least in the case of Padding, if you don't include Padding on your ControlTemplate TemplateBinding, you won't be able to override it on your element.

此外,对于边距,如果在 ControlTemplate TemplateBinding 中包含边距,似乎会发生某种加倍"效果.如果您不使用模板屏蔽边距,您仍然可以覆盖边距,但行为会发生变化.

Additionally, in the case of margin, there seems to be some kind of "doubling" effect that happens if you include Margin in the ControlTemplate TemplateBinding. If you don't templateblind the margin, you can still override margin but the behavior changes.

第一步

使用 ControlTemplate 定义基本样式.确保您的 ControlTemplate 包含您可能希望在单个元素上自定义/覆盖的所有属性的 TemplateBinding.

Define a base style with a ControlTemplate. Make sure that your ControlTemplate includes a TemplateBinding for all properties that you may want to customize/override on individual elements.

<Style TargetType="Button">
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Background" Value="{StaticResource BaseButtonBG}"/>
    <Setter Property="Margin" Value="0"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border 
                    Background="{TemplateBinding Background}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}"
                    Margin="{TemplateBinding Margin}"
                    >
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="{StaticResource BaseButtonBG_IsMouseOver}"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Background" Value="{StaticResource BaseButtonBG_IsPressed}"/>
        </Trigger>
    </Style.Triggers>
</Style>

我已经为我的属性颜色定义了一些 StaticResource 键,这样我就可以将它们完全放在另一个地方,以实现更清洁的蒙皮.以下是这些键:

I've defined a few StaticResource keys for my property colors so that I can put them altogether in another place for cleaner skinning. Here are those keys:

<SolidColorBrush x:Key="BaseButtonBG"                   Color="#5f636c"/>
<SolidColorBrush x:Key="BaseButtonBG_IsMouseOver"       Color="#898C94"/>
<SolidColorBrush x:Key="BaseButtonBG_IsPressed"         Color="#484B51"/>

第 2 步

像这样实现实际的按钮:

Implement actual button like this:

<Button Content="New" />

这样做的结果是一个看起来像这样的按钮:

And the result of this makes a button that looks like this:

步骤 3

现在假设我希望我的所有按钮看起来都像这样被压扁,只有一个除外.我想添加一些垂直填充以使特定按钮看起来更高.我可以像这样更改示例按钮:

Now let's say I want all of my buttons to look squashed like that, except one. I want to add some vertical padding to make one specific button look taller. I could alter the example button like this:

<Button Content="New" Padding="0,30"/>

结果:

或者,您可以按如下方式实现按钮覆盖,这使您能够覆盖触发器或其他特殊样式选项.

Alternatively, you could implement the button override as follows, which gives you the ability to override Triggers or other special Style options.

<Button Content="New">
    <Button.Style >
        <Style TargetType="Button" BasedOn="{DynamicResource {x:Type Button}}">
            <Setter Property="Padding" Value="0,30"/>
        </Style>
    </Button.Style>
</Button>

多田!我们已将一次性样式调整直接分配给它所属的元素!我们不必在字典中创建样式并在这种情况下引用它.

重要事项

为了使这项工作填充"必须在 ControlTemplate 中用 TemplateBinding 代码定义.如果您不这样做,则直接应用于按钮的 Padding 将被完全忽略.同样,我不确定为什么会这样,但这似乎是一个神奇的解决方案.

In order to make this work "Padding" MUST BE defined in the ControlTemplate with the TemplateBinding code. If you don't do that, Padding directly applied to the button just gets ignored completely. Again, I'm not sure why its like this, but that seems to be the magic fix.

进一步阅读:我从这篇博客文章的一些有用信息中了解到这一点:

Further Reading: I was able to figure this out from some helpful info on this blog article:

explicit-implicit-and-and-wpf 中的默认样式

有趣的是,该文章的最后一部分建议使用您自己的默认样式和属性创建自定义控件,您可以像我在这里所做的那样覆盖这些控件.这对我来说似乎有点矫枉过正,但它可能会消除填充和边距行为不同的奇怪错误问题.不过还没试过.

Interestingly, the last part of that article suggests creating a custom control with your own default style and properties that you can override similarly to how I've done here. This seems a bit overkill to me, but it might eliminate the weird bugginess problem with padding and margin behaving differently. Haven't tried that yet, though.

这篇关于如何设置覆盖 WPF 中全局样式的特定控制元素设置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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