使用 Windows Presentation Foundation (WPF),可以使用自己的可重用样式自定义现有控件的外观。 样式可以全局应用于应用、窗口和页面,也可以直接应用于控件。
创建样式
可以将一种 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>
样式由子元素组成,这些子元素用于设置样式应用到的元素的属性。 在上面的示例中,请注意,样式设置为通过TargetType
属性应用于TextBlock
类型。 样式将设置为 FontSize to 15
和 FontWeight to 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>
将样式TextBlock设置为TargetType类型并省略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 标记扩展将元素上的属性设置为Stylex: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。 因此,必须先将检索到的样式转换为System.Windows.Style,然后再将其分配给Style
属性。 例如,以下代码将命名textblock1
的TextBlock
样式设置为定义的样式TitleText
。
textblock1.Style = (Style)Resources["TitleText"];
textblock1.Style = CType(Resources("TitleText"), Windows.Style)
扩展样式
也许你希望两个 TextBlock 元素共享一些属性值,例如居中的 FontFamily 和 HorizontalAlignment。 但你还希望 文本“我的图片” 具有一些其他属性。 为此,可以创建基于第一个样式的新样式,如下所示。
<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>
然后,将样式应用于 TextBlock
。
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
此 TextBlock
样式现在居中,使用 Comic Sans MS
大小为 26
和前景色设置为 LinearGradientBrush 示例中所示的字体。 请注意,它覆盖了基本样式的 FontSize 值。 如果在Style中有多个Setter指向同一属性,则最后声明的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
元素。 如果样式位于 resources 节中,并且未在样式上设置 TargetType
属性,则必须设置 x:Key
该属性。
除了为x:Key
提供默认值以外,TargetType
属性还指定 setter 属性应用的类型。 如果未指定属性TargetType
,则必须使用语法Property="ClassName.Property"
限定对象中的Setter属性和类名。 例如,您必须将Property="FontSize"
设置为"TextBlock.FontSize"
或"Control.FontSize"
,而不是设置Property。
另请注意,许多 WPF 控件由其他 WPF 控件的组合组成。 如果创建适用于类型的所有控件的样式,可能会获得意外的结果。 例如,如果在