首页 > 解决方案 > 为什么 WPF 样式标签会覆盖我的按钮的背景颜色和其他属性?

问题描述

假设我在 WPF 应用程序中有一个简单的按钮,位于灰色背景的网格中:

在此处输入图像描述

<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Hello" Width="100" Height="50" Background="#333333" BorderThickness="0"/> 

我想通过添加以下代码来更改按钮的 MouseOver 行为:

<Button.Style>
    <Style TargetType="{x:Type Button}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border>
                        <Border.Style>
                            <Style TargetType="{x:Type Border}">
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Background" Value="#404040"/>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Border.Style>
                        <Grid Background="Transparent">
                            <ContentPresenter></ContentPresenter>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Button.Style>

问题是:为什么添加这个样式标签会改变颜色和移动文本?

在此处输入图像描述

标签: c#wpfxamlcontroltemplate

解决方案


WPF 中的AControlTemplate定义控件的外观和视觉状态,例如鼠标悬停或聚焦。如果您覆盖控制模板,您将从头开始。您不能只覆盖特定部分,例如鼠标悬停状态而忽略其余部分。控件将无法正常工作。您必须重新创建整个控件模板或采用默认模板并对其进行调整。

每个控件都有一个默认模板,通常根据给定的要求提取和修改。您可以在 MSDN 上找到控制模板的所有部分、状态和一些示例,例如Button. 如果您没有实现任何已定义的状态或部分,您的按钮可能无法按预期运行,正如您已经注意到的那样。

MSDN 上的控制模板示例可能不完整或已过时。您可以使用 Blend 或 Visual Studio 提取默认控件模板。有关这方面的说明,请参阅此相关帖子

问题是:为什么添加这个样式标签会改变颜色和移动文本?

模板中的Background任何控件都获得其默认值、您明确分配的值或标记扩展或绑定提供的值。在您的示例中,所有背景值要么丢失,因此是默认值,要么是硬编码的。

如果您想使用定义在模板上的背景颜色Button,您必须使用 aTemplateBindingRelativeSource绑定TemplatedParent,例如在您的Border

<Border Background="{TemplateBinding Background">

这会将Background分配给模板化按钮的值(直接或通过 a Style)应用到您的Border. 本质上,模板绑定可以为您的控件设置样式。

为什么文字被移动了?那只是因为您没有以其他方式定义它。请记住,您要从头开始。尝试ContentPresenter像这样设置,你会看到Content居中:

<ContentPresenter HorizontalAlignment="Center"
                  VerticalAlignment="Center"/>

关于鼠标悬停风格的另一句话。在控件模板中,您可以使用VisualStateManager或通过在控件模板上定义触发器来定义状态。

例如,对于鼠标悬停状态,您将首先为您的 分配一个名称Border

<Border x:Name="ButtonBorder" ... >

然后,您可以将触发器添加到引用此名称的控件模板以设置Background

<ControlTemplate.Triggers>
   <Trigger Property="IsMouseOver" Value="True">
      <Setter TargetName="ButtonBorder" Property="Background" Value="#404040"/>
   </Trigger>
</ControlTemplate.Triggers>

控制模板不是很简单而且很容易得到正确的。我建议您阅读这篇关于创建控件模板的介绍,以更好地了解它们的工作原理。


推荐阅读