如何设置特定的控件元素设置来覆盖WPF中的全局样式?

时间:2019-02-02 17:06:20

标签: wpf xaml

我已经通过应用程序范围的资源字典为应用程序中的Button定义了全局样式。样式如下(继另一个SO示例之后):

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

有效。但是我需要直接为某些按钮分配特定的值,例如边距和填充以使其对齐。我还希望能够从单个按钮的样式中覆盖颜色属性。

看来,我直接在特定按钮上设置的所有属性都将被完全忽略,而仅使用全局样式中的属性。我该如何克服?

更新:澄清我想要的内容:  在HTML / CSS世界(比污垢更旧的世界)中,可以将样式类添加到元素,但是也可以将属性直接分配给覆盖类值的元素。这就是我要在WPF中完成的工作。

更新2 人们可能认为这个问题很愚蠢,因为解决方案应该很明显。但是,从我的个人测试来看,除非您将其专门绑定到控件模板中,否则Padding似乎根本不会更改。这种现象似乎因财产而异。由于我最初尝试覆盖某个属性的尝试特别涉及到Padding,但它没有用,所以我不得不构建此变通方法。

2 个答案:

答案 0 :(得分:0)

好的,设计中的表单:

enter image description here

表单的XAML代码:

<Window.Resources>

    <Style TargetType="Button">
        <Setter Property="Foreground" Value="Red"/>
        <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>
</Window.Resources>


<Grid>
    <Button Content="Button" x:Name="btnNo1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120"/>
    <Button Content="Button" x:Name="btnNo2" HorizontalAlignment="Left" Margin="135,10,0,0" VerticalAlignment="Top" Width="120"/>

</Grid>

,然后在运行时中,通过在CS文件中使用以下代码来更改Margin

public MainWindow()
{
    InitializeComponent();

    btnNo2.Margin = new Thickness(100, 100, 100, 100);
}

结果将是:

enter image description here



可以在需要自定义边距/填充的按钮上创建和使用新样式吗?

<Style x:Key="SpecialButtonType1" BasedOn="{StaticResource ResourceKey=CommonButtonStyle}">
...
</Style>

并更改

<Style TargetType="Button">

<Style TargetType="Button" x:Key="CommonButtonStyle">

答案 1 :(得分:0)

是的,这是完全可行的,您可以直接在元素上分配覆盖属性,而无需进行很多过程,即为有问题的特定元素创建特殊的一次性字典条目所使用的丑陋过程。

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

您的词典引用的基本样式可能需要包含您要覆盖的所有属性。由于某些原因,不同的属性似乎表现出不同的行为。但至少在填充的情况下,如果不包括填充你的控件模板TemplateBinding,您将无法对其进行重写你的元素。

此外,在保证金的情况下,似乎有某种“倍增”效应,如果你包括在ControlTemplate中TemplateBinding保证金出现这种情况。如果您不对边距进行模板盲处理,则仍然可以覆盖边距,但是行为会发生变化。

STEP 1

定义与的ControlTemplate一个基本样式。确保您的ControlTemplate为您可能希望自定义/覆盖各个元素的所有属性包括一个TemplateBinding。

<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键,以便可以将它们一起放置在另一个地方以使外观更加整洁。下面是这些键:

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

STEP 2

实施这样实际的按钮:

<Button Content="New" />

其结果是使按钮看起来像这样:

Initial Button Style

<强>第3步

现在让我说,我希望所有按钮都像那样被压扁,除了一个。我想添加一些垂直填充以使一个特定的按钮看起来更高。我可以改变例如按钮这样的:

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

结果:

Altered Button Style

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

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

TADA!我们直接将一次性调整样式分配给元素“哪里”!在这种情况下,我们不必在字典中创建样式并引用它。

重要点

为了使这项工作有效,必须在ControlTemplate中使用TemplateBinding代码定义“填充”。如果不这样做,直接应用于按钮的填充将被完全忽略。再次,我不确定为什么会这样,但这似乎是魔术。

进一步阅读:通过这篇博客文章中的一些有用信息,我能够弄清楚这一点:

explicit-implicit-and-default-styles-in-wpf

有趣的是,该文章的最后一部分建议使用您自己的默认样式和属性创建一个自定义控件,您可以像在此所做的操作一样覆盖这些控件。对我来说,这似乎有些矫kill过正,但它可以消除填充和边距行为不同的怪异的错误问题。并没有说的是,虽然。