Styles 样式
Inline Styles 内联样式
<Button Margin="0,0,2,2" Grid.Row="0" Grid.Column="0" Name="cell00" > <Button.Style> <Style> <Setter Property="Button.FontSize" Value="32pt"/> <Setter Property="Button.FontWeight" Value="Bold"/> </Style> </Button.Style> </Button>
内联样式实际上涉及的输入不仅仅是设置属性,而且内联样式无法在元素之间共享。因此,内联样式的使用频率不如命名样式。
但是,如果您想向单个元素添加属性和数据触发器,则内联样式很有用
Named Styles 命名样式
通过将相同的内联样式提升到资源中,我们可以授予它一个名称并在我们的按钮实例中按名称引用它
<Window.Resources> <Style x:Key="CellTextStyle" > <Setter Property="Control.FontSize" Value="32pt"/> <Setter Property="Control.FontWeight" Value="Bold"/> </Style> </Window.Resources>
<Button Style="{StaticResource CellTextStyle}" Margin="2,0,2,2" Grid.Row="0" Grid.Column="1" Name="cell01" />
The Target Type Attribute 目标类型样式
所有属性都可以在一个共享基类上设置
<Style x:Key="CellTextStyle" TargetType="{x:Type Control}" > <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> </Style>
覆盖特定实例的样式属性,我们可以通过设置该实例的属性来实现
<Style x:Key="CellTextStyle"> <Setter Property="TextElement.FontSize" Value="32pt" /> <Setter Property="TextElement.FontWeight" Value="Bold" /> </Style> ... <TextBlock Style="{StaticResource CellTextStyle}" FontWeight="Normal" ... />
Extending Styles 扩展样式
除了重用和覆盖现有样式的能力之外,您还可以扩展样式、添加新属性或覆盖现有样式
<Style x:Key="CellTextStyle"> <Setter Property="Control.FontSize" Value="32pt" /> <Setter Property="Control.FontWeight" Value="Bold" /> </Style> <Style x:Key="StatusTextStyle" BasedOn="{StaticResource CellTextStyle}"> <Setter Property="TextBlock.FontWeight" Value="Normal" /> <Setter Property="TextBlock.Foreground" Value="White" /> <Setter Property="TextBlock.HorizontalAlignment" Value="Center" /> </Style>
Setting Styles Programmatically 以编程方式设置样式
<Style x:Key="XStyle" BasedOn="{StaticResource CellTextStyle}"> <Setter Property="ItemsControl.Foreground" Value="Red"/> </Style> <Style x:Key="OStyle" BasedOn="{StaticResource CellTextStyle}"> <Setter Property="Control.Foreground" Value="Green"/> </Style>
// Switch player if (CurrentPlayer == "X") { button.Style = (Style)FindResource("XStyle"); CurrentPlayer = "O"; } else { button.Style = (Style)FindResource("OStyle"); CurrentPlayer = "X"; }
请注意,X 和 O 是根据命名的球员风格着色的。在这种特殊情况下(以及许多其他情况下),数据触发器应该优先于以编程方式设置样式,但我们稍后会谈到。
Element-Typed Styles 元素类型样式
当您有一组要应用于特定元素实例的属性时,命名样式很有用。但是,如果您希望将一种样式统一应用于某种类型元素的所有实例,请设置不带Key的TargetType
<!--当有设置键和目标类型时,控件引用时必须设置 Style 属性值为键名--> <Style x:Key="StatusTextStyle" TargetType="{x:Type TextBlock}"> <Setter Property="FontSize" Value="23pt"/> <Setter Property="FontWeight" Value="Normal"/> <Setter Property="Foreground" Value="White"/> <Setter Property="HorizontalAlignment" Value="Center"/> </Style>
<!--没有设置键时,当前样式自动应用于全部 Button--> <Style TargetType="{x:Type Button}"> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> </Style>
当您希望某个元素的所有实例共享一个外观时,元素类型样式就很方便,具体取决于范围
将按钮样式的范围限定在网格内同样有效,这样只有网格中的按钮受到影响
<!-- Window1.xaml --> <Window ...> <Grid ...> <!-- only Buttons in the Grid are affected --> <Grid.Resources> <Style TargetType="{x:Type Button}">...</Style> </Grid.Resources> ... </Grid> <!-- Buttons outside the Grid are unaffected --> ... </Window>
如果你想让你的风格在你的项目中有更大的影响力,你可以把它放到应用程序范围内
<!-- MyApp.xaml --> <Application ...> <!-- every Button in the Application is affected --> <Application.Resources> <Style TargetType="{x:Type Button}">...</Style> </Application.Resources> </Application>
样式继承
TargetType 类型的样式,不会应用于派生类,但可以通过 BasedOn 实现继承样式
<Window.Resources> <Style x:Key="toggleButtonStyle" TargetType="ToggleButton"> <Setter Property="FontSize" Value="32" /> </Style> <Style TargetType="RadioButton" BasedOn="{StaticResource toggleButtonStyle}" /> <Style TargetType="CheckBox" BasedOn="{StaticResource toggleButtonStyle}" /> </Window.Resources>
Data Templates and Styles 数据模板和样式
* 在 WPF 中使用内容模型的控件是那些带有使用ContentPresenter 的控件模板的控件
button.Content=new PlayerMove(this.CurrentPlayer, ++this.moveNumber);
<Window.Resources> <Style x:Key="CellTextStyle" TargetType="{x:Type TextBlock}" > <Setter Property="FontSize" Value="32pt" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" /> </Style> <Style x:Key="MoveNumberStyle" TargetType="{x:Type TextBlock}"> <Setter Property="FontSize" Value="16pt" /> <Setter Property="FontStyle" Value="Italic" /> <Setter Property="VerticalAlignment" Value="Bottom" /> <Setter Property="HorizontalAlignment" Value="Right" /> </Style> <DataTemplate DataType="{x:Type local:PlayerMove}"> <Grid> <TextBlock Text="{Binding Path=PlayerName}" Style="{StaticResource CellTextStyle}" /> <TextBlock Text="{Binding Path=MoveNumber}" Style="{StaticResource MoveNumberStyle}"/> </Grid> </DataTemplate> </Window.Resources>
Triggers 触发器
属性触发器是一种在条件中包装一个或多个Setter元素的方法。使用属性触发器,如果条件为真,则执行相应的Setter元素以设置一个或多个元素属性。当条件变为假时,属性值恢复到它们的预触发值。
属性触发器并不是 WPF 支持的唯一类型的触发器。使用事件触发器,触发器在触发事件时激活,触发另一个事件以启动或停止动画。
Property Triggers 属性触发器
简单的属性触发器
<Style TargetType="{x:Type Button}"> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Style.Triggers> <Trigger Property="Content" Value="{x:Null}"> <Setter Property="ToolTip" Value="click to move here"/> </Trigger> </Style.Triggers> </Style>
多个触发器
<Style TargetType="{x:Type Button}"> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Style.Triggers> <Trigger Property="Content" Value="{x:Null}"> <Setter Property="ToolTip" Value="click to move here"/> </Trigger> <Trigger Property="IsFocused" Value="True"> <Setter Property="ToolTip" Value="click or spacebar to move here"/> </Trigger> </Style.Triggers> </Style>
多条件触发器
<Style.Triggers> <Trigger Property="Content" Value="{x:Null}"> <Setter Property="ToolTip" Value="click to move here"/> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsFocused" Value="True"/> <Condition Property="Content" Value="{x:Null}"/> </MultiTrigger.Conditions> <Setter Property="ToolTip" Value="click or spacebar to move here"/> </MultiTrigger> </Style.Triggers> </Style>
Data Triggers 数据触发器
属性触发器通常用于检查 WPF 可视元素属性,而数据触发器通常用于检查用作内容的非可视对象的属性
<Style x:Key="CellTextStyle" TargetType="{x:Type TextBlock}" > <Setter Property="FontSize" Value="32pt" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Style.Triggers> <DataTrigger Binding="{Binding Path= PlayerName}" Value="X"> <Setter Property="Foreground" Value="Yellow"/> </DataTrigger> <DataTrigger Binding="{Binding Path=PlayerName}" Value="O"> <Setter Property="Foreground" Value="Blue"/> </DataTrigger> </Style.Triggers> </Style>
<DataTemplate DataType="{x:Type local:PlayerMove}"> <Grid> <TextBlock Text="{Binding Path=PlayerName}" Style="{StaticResource CellTextStyle}" /> <TextBlock Text="{Binding Path=MoveNumber}" Style="{StaticResource MoveNumberStyle}"/> </Grid> </DataTemplate>
多条件数据触发器
<Style x:Key="MoveNumberStyle" TargetType="{x:Type TextBlock}"> <Setter Property="FontSize" Value="16pt" /> <Setter Property="FontStyle" Value="Italic" /> <Setter Property="VerticalAlignment" Value="Bottom" /> <Setter Property="HorizontalAlignment" Value="Right" /> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=PlayerName}" Value="X"/> <Condition Binding="{Binding Path=IsPartOfWin}" Value="True"/> </MultiDataTrigger.Conditions> <Setter Property="BitmapEffect"> <Setter.Value> <OuterGlowBitmapEffect GlowColor="Red" GlowSize="10"/> </Setter.Value> </Setter> <Setter Property="FontSize" Value="50"/> </MultiDataTrigger> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=PlayerName}" Value="O"/> <Condition Binding="{Binding Path=IsPartOfWin}" Value="True"/> </MultiDataTrigger.Conditions> <Setter Property="BitmapEffect"> <Setter.Value> <OuterGlowBitmapEffect GlowColor="Green" GlowSize="10"/> </Setter.Value> </Setter> <Setter Property="FontSize" Value="50"/> </MultiDataTrigger> </Style.Triggers> </Style>
<DataTemplate DataType="{x:Type local:PlayerMove}"> <Grid> <TextBlock Text="{Binding Path=PlayerName}" Style="{StaticResource CellTextStyle}" /> <TextBlock Text="{Binding Path=MoveNumber}" Style="{StaticResource MoveNumberStyle}"/> </Grid> </DataTemplate>
Event Triggers 事件触发器
属性触发器检查依赖属性的值,数据触发器检查 CLR 属性的值,而事件触发器则监视事件。当事件(如Click事件)发生时,事件触发器通过引发与动画相关的事件来响应。
<Style TargetType="{x:Type Button}"> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Style.Triggers> <Trigger Property="Content" Value="{x:Null}"> <Setter Property="ToolTip" Value="click to move here"/> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsFocused" Value="True"/> <Condition Property="Content" Value="{x:Null}"/> </MultiTrigger.Conditions> <Setter Property="ToolTip" Value="click or spacebar to move here"/> </MultiTrigger> <EventTrigger RoutedEvent="Click"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:2"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style>
事件触发器让您可以在事件发生时触发动画。属性和数据触发器允许您在属性更改时设置属性,
但它们也允许您启动或停止动画。这两种类型的触发器都可以让您以一种美妙的声明方式为您的应用程序添加一定程度的交互性,而无需或只需很少的代码。