c# - 为什么 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>
问题是:为什么添加这个样式标签会改变颜色和移动文本?
解决方案
WPF 中的AControlTemplate
定义控件的外观和视觉状态,例如鼠标悬停或聚焦。如果您覆盖控制模板,您将从头开始。您不能只覆盖特定部分,例如鼠标悬停状态而忽略其余部分。控件将无法正常工作。您必须重新创建整个控件模板或采用默认模板并对其进行调整。
每个控件都有一个默认模板,通常根据给定的要求提取和修改。您可以在 MSDN 上找到控制模板的所有部分、状态和一些示例,例如Button
. 如果您没有实现任何已定义的状态或部分,您的按钮可能无法按预期运行,正如您已经注意到的那样。
MSDN 上的控制模板示例可能不完整或已过时。您可以使用 Blend 或 Visual Studio 提取默认控件模板。有关这方面的说明,请参阅此相关帖子。
问题是:为什么添加这个样式标签会改变颜色和移动文本?
模板中的Background
任何控件都获得其默认值、您明确分配的值或标记扩展或绑定提供的值。在您的示例中,所有背景值要么丢失,因此是默认值,要么是硬编码的。
如果您想使用定义在模板上的背景颜色Button
,您必须使用 aTemplateBinding
或RelativeSource
绑定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>
控制模板不是很简单而且很容易得到正确的。我建议您阅读这篇关于创建控件模板的介绍,以更好地了解它们的工作原理。
推荐阅读
- android - Android 4.4 (Kitkat) 上的 Ionic3 MainActivity ClassNotFoundException
- debian - Debian Stretch:无法卸载bonescript
- javascript - 为什么我得到:必须使用解构状态分配?
- django - Python,Django 2.1 - 请提供建议和指导
- java - Android应用程序在屏幕锁定一段时间后被杀死
- php - 将php密码哈希转换为原始值是可能的吗?
- flutter - Flutter:如何在创建类时最好地实例化 SQFlite db 对象
- r - 在R中使用停止字符拆分字符串
- python - 如何在 python 中为数据库创建可分发的 RESTful API?
- firebase - 为 null 时的 Cloud Firestore 自定义声明