为什么 WPF 样式标签会覆盖按钮的背景颜色和其他属性?
Why WPF style tag overrides the background color and other properties of my button?
假设我在灰色背景的网格中的 WPF 应用程序中有一个简单的按钮:
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Hello" Width="100" Height="50" Background="#333333" BorderThickness="0"/>
我想通过添加以下代码来更改按钮的鼠标悬停行为:
<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 中的 ControlTemplate
定义控件的外观和视觉状态,如 mouse-over 或焦点。如果覆盖控件模板,则需要从头开始。您不能仅覆盖特定部分,例如 mouse-over 状态而忽略其余部分。控件将无法正常工作。您必须重新创建整个控件模板或采用默认模板并进行调整。
每个控件都有一个默认模板,通常根据给定的要求提取和修改。您可以在 MSDN e.g. for Button
上找到所有部件、状态和一些控件模板示例。如果您没有实现任何已定义的状态或部分,您的按钮可能不会按预期运行,正如您已经注意到的那样。
MSDN 上的控件模板示例可能不完整或已过时。您可以使用 Blend 或 Visual Studio 提取默认控件模板。有关说明,请参阅此 related post.
The problem is: why the color changed and the text moved by adding this style tag?
模板中任何控件的 Background
都将获得其默认值、您明确分配的值或标记扩展或绑定提供的值。在您的示例中,所有背景值要么缺失(因此默认),要么硬编码。
如果您想使用模板 Button
上定义的背景颜色,您必须使用 TemplateBinding
or a RelativeSource
binding on TemplatedParent
,例如在你的 Border
:
<Border Background="{TemplateBinding Background">
这会将分配给模板化按钮(直接或通过 Style
)的 Background
的值应用到您的 Border
。本质上,模板绑定可以为您的控件设置样式。
为什么文本被移动了?那只是因为您没有以其他方式定义它。请记住,您是从头开始的。尝试像这样设置 ContentPresenter
,您会看到 Content
居中:
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
关于您的 mouse-over 风格的另一评论。在控件模板中,您可以使用 VisualStateManager
or by defining triggers on your control template.
定义状态
例如,对于 mouse-over 状态,您首先要为 Border
:
分配一个名称
<Border x:Name="ButtonBorder" ... >
然后您可以将触发器添加到引用此名称的控件模板以设置 Background
:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="#404040"/>
</Trigger>
</ControlTemplate.Triggers>
控件模板并不简单且易于正确使用。我建议您阅读此 introduction to creating control templates 以更好地了解它们的工作原理。
假设我在灰色背景的网格中的 WPF 应用程序中有一个简单的按钮:
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Hello" Width="100" Height="50" Background="#333333" BorderThickness="0"/>
我想通过添加以下代码来更改按钮的鼠标悬停行为:
<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 中的 ControlTemplate
定义控件的外观和视觉状态,如 mouse-over 或焦点。如果覆盖控件模板,则需要从头开始。您不能仅覆盖特定部分,例如 mouse-over 状态而忽略其余部分。控件将无法正常工作。您必须重新创建整个控件模板或采用默认模板并进行调整。
每个控件都有一个默认模板,通常根据给定的要求提取和修改。您可以在 MSDN e.g. for Button
上找到所有部件、状态和一些控件模板示例。如果您没有实现任何已定义的状态或部分,您的按钮可能不会按预期运行,正如您已经注意到的那样。
MSDN 上的控件模板示例可能不完整或已过时。您可以使用 Blend 或 Visual Studio 提取默认控件模板。有关说明,请参阅此 related post.
The problem is: why the color changed and the text moved by adding this style tag?
模板中任何控件的 Background
都将获得其默认值、您明确分配的值或标记扩展或绑定提供的值。在您的示例中,所有背景值要么缺失(因此默认),要么硬编码。
如果您想使用模板 Button
上定义的背景颜色,您必须使用 TemplateBinding
or a RelativeSource
binding on TemplatedParent
,例如在你的 Border
:
<Border Background="{TemplateBinding Background">
这会将分配给模板化按钮(直接或通过 Style
)的 Background
的值应用到您的 Border
。本质上,模板绑定可以为您的控件设置样式。
为什么文本被移动了?那只是因为您没有以其他方式定义它。请记住,您是从头开始的。尝试像这样设置 ContentPresenter
,您会看到 Content
居中:
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
关于您的 mouse-over 风格的另一评论。在控件模板中,您可以使用 VisualStateManager
or by defining triggers on your control template.
例如,对于 mouse-over 状态,您首先要为 Border
:
<Border x:Name="ButtonBorder" ... >
然后您可以将触发器添加到引用此名称的控件模板以设置 Background
:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="#404040"/>
</Trigger>
</ControlTemplate.Triggers>
控件模板并不简单且易于正确使用。我建议您阅读此 introduction to creating control templates 以更好地了解它们的工作原理。