使用 Windows Presentation Foundation (WPF),可以使用自己的可重用样式自定义现有控件的外观。 可以对应用、窗口和页面全局应用样式,也可以将样式直接应用于控件。
面向 .NET 7 和 .NET 6 的桌面指南文档正在撰写中。
可以将
Style
视为一种将一组属性值应用到一个或多个元素的便利方法。 可以对从
FrameworkElement
或
FrameworkContentElement
(如
Window
或
Button
)派生的任何元素使用样式。
声明样式的最常见方法是在 XAML 文件的
Resources
部分中声明为资源。 样式是一种资源,因此它们遵从适用于所有资源的相同范围规则。 简而言之,声明样式的位置会影响样式的应用范围。 例如,如果在应用定义 XAML 文件的根元素中声明样式,则该样式可以在应用中的任何位置使用。
<Application x:Class="IntroToStylingAndTemplating.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="WindowExplicitStyle.xaml">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
如果在应用的一个 XAML 文件中声明样式,则该样式只能在该 XAML 文件中使用。 有关资源的范围规则的详细信息,请参阅
XAML 资源概述
。
<Window x:Class="IntroToStylingAndTemplating.WindowSingleResource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="WindowSingleResource" Height="450" Width="800">
<Window.Resources>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</Window.Resources>
<Grid />
</Window>
样式由
<Setter>
子元素组成,这些元素在应用了样式的元素上设置属性。 在上面的示例中,请注意,样式已设置为通过
TargetType
属性应用于
TextBlock
类型。 样式会将
FontSize
设置为
15
,并将
FontWeight
设置为
ExtraBold
。 为样式更改的每个属性添加一个
<Setter>
。
隐式应用样式
Style
是一种将一组属性值应用到多个元素的便利方法。 例如,请考虑以下
TextBlock
元素及其在窗口中的默认外观。
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
可以通过直接对每个
TextBlock
元素设置属性(如
FontSize
和
FontFamily
)来更改默认外观。 但是,如果需要让
TextBlock
元素共享某些属性,可以在 XAML 文件的
Resources
部分中创建
Style
,如下所示。
<Window.Resources>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
将样式的
TargetType
设置为
TextBlock
类型并省略
x:Key
属性时,该样式将应用到样式的所有
TextBlock
元素,通常是 XAML 文件本身。
现在
TextBlock
元素如下所示。
显式应用样式
如果向样式添加具有值的
x:Key
属性,则样式将不再隐式应用于
TargetType
的所有元素。 只有显式引用样式的元素才会应用样式。
下面是上一节中的样式,但使用
x:Key
属性进行了声明。
<Window.Resources>
<Style x:Key="TitleText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
若要应用样式,请使用
StaticResource 标记扩展
将元素上的
Style
属性设置为
x:Key
值,如下所示。
<StackPanel>
<TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
请注意,第一个
TextBlock
元素已应用样式,而第二个 TextBlock 元素保持不变。 上一节中的隐式样式已更改为声明了
x:Key
属性的样式,也就是说,该样式影响的唯一元素是直接引用该样式的那个元素。
在显式或隐式应用样式后,它将变为密封状态,不能更改。 如果要更改已应用的样式,请创建新的样式来替换现有样式。 有关更多信息,请参见
IsSealed
属性。
可以创建一个根据自定义逻辑选择要应用的样式的对象。 有关示例,请参阅为
StyleSelector
类提供的示例。
以编程方式应用样式
若要以编程方式将已命名的样式分配到元素,请从资源集合中获取样式,并将其分配到元素的
Style
属性。 资源集合中的项属于
Object
类型。 因此,在将检索到的样式分配给
Style
属性之前,必须将它强制转换为
System.Windows.Style
。 例如,下面的代码将名为
textblock1
的
TextBlock
的样式设置为定义的样式
TitleText
。
textblock1.Style = (Style)Resources["TitleText"];
textblock1.Style = CType(Resources("TitleText"), Windows.Style)
也许你希望两个
TextBlock
元素共享某些属性值,如
FontFamily
和居中的
HorizontalAlignment
。 你可能还希望文本“My Pictures” 具有一些其他属性。 可以通过创建基于第一个样式的新样式来实现此目的,如下所示。
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
此
TextBlock
样式现在居中,使用大小为
26
的
Comic Sans MS
字体,并将前景色设置为如示例中显示的
LinearGradientBrush
。 请注意,它会重写基本样式的
FontSize
值。 如果有多个
Setter
指向
Style
中的同一属性,则最后声明的
Setter
优先。
TextBlock
元素现在如下所示:
此
TitleText
样式扩展为
TextBlock
类型创建的样式,该样式由
BasedOn="{StaticResource {x:Type TextBlock}}"
引用。 还可以使用样式的
x:Key
扩展具有
x:Key
的样式。 例如,如果有一个名为
Header1
的样式,并且你需要扩展该样式,可以使用
BasedOn="{StaticResource Header1}"
。
TargetType 属性与 x:Key 属性之间的关系
如前所述,将
TargetType
属性设置为
TextBlock
时,如果不为样式分配
x:Key
,会导致将样式应用于所有
TextBlock
元素。 在此情况下,
x:Key
隐式设置为
{x:Type TextBlock}
。 这意味着,如果将
x:Key
值显式设置为除
{x:Type TextBlock}
以外的任何值,则
Style
不会自动应用于所有
TextBlock
元素。 相反,必须将该样式(通过使用
x:Key
值)显式应用到
TextBlock
元素。 如果你的样式位于资源部分中,并且你未对样式设置
TargetType
属性,则必须设置
x:Key
属性。
除了为
x:Key
提供默认值以外,
TargetType
属性还指定 setter 属性应用到的类型。 如果不指定
TargetType
,则必须使用语法
Property="ClassName.Property"
,通过类名称限定
Setter
对象中的属性。 例如,必须将
Property
设置为
"TextBlock.FontSize"
或
"Control.FontSize"
,而不是设置
Property="FontSize"
。
另请注意,许多 WPF 控件由其他 WPF 控件的组合构成。 如果创建应用于某个类型的所有控件的样式,可能会产生意外结果。 例如,如果创建一个样式,该样式以
Window
中的
TextBlock
类型为目标,那么,即使
TextBlock
是另一个控件(如
ListBox
)的一部分,该样式也将应用于窗口中的所有
TextBlock
控件。
如何创建控件模板
XAML 资源概述
XAML概述