10-2.WPF的Style
构成Style的最重要两个元素是Setter和Trigger,Setter设置控件的静态外观风格,Trigger设置控件的行为风格。
Setter
Property指明为目标的哪个属性赋值,Value则是提供属性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <Window x:Class="WpfApplication1.Window40" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window40" Height="310" Width="426"> <Window.Resources> <Style TargetType="TextBlock"> <Setter Property="FontSize" Value="24"></Setter> <Setter Property="TextDecorations" Value="Underline"></Setter> <Setter Property="FontStyle" Value="Italic"></Setter> </Style> </Window.Resources> <StackPanel Margin="5"> <TextBlock Text="Hello WPF!"></TextBlock> <TextBlock Text="This is a sample for style!"></TextBlock> <TextBlock Text="by Time 2012-11-12!" Style="{x:Null}"></TextBlock> </StackPanel> </Window>
|

如果想设置控件的ControlTemplate,只需要把Setter的Property设为Template并为Value提供一个ControlTemplate对象即可。
Trigger
当满足某些条件会触发的行为,触发器比较像事件,事件一般由用户触发,而Trigger除了有事件触发的EventTrigger外,还有数据变化触发形的Trigger/DataTrigger以及多条件触发形的MultiTrigger/MultiDataTrigger等。
基本Trigger
类似Setter,也有Property和Value两个属性,Property是关注的属性名称,Value是触发条件,Trigger类还有一个Setters属性,这是一组Setter当触发条件,这组Setters就会被应用。
案例:当勾选了目标时,字体和颜色会改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <Window x:Class="WpfApp5.MainWindow" 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:WpfApp5" mc:Ignorable="d" Title="MainWindow" Height="150" Width="300"> <Window.Resources> <Style TargetType="CheckBox"> <Style.Triggers> <Trigger Property="IsChecked" Value="true"> <Trigger.Setters> <Setter Property="FontSize" Value="20"/> <Setter Property="Foreground" Value="Orange"/> </Trigger.Setters> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <CheckBox Content="A" Margin="5"/> <CheckBox Content="B" Margin="5"/> <CheckBox Content="C" Margin="5"/> <CheckBox Content="D" Margin="5"/> </StackPanel> </Window>
|

MultiTrigger
多个条件同时成立才会触发,MultiTrigger具有一个Conditions属性,该属性指明要同时成立的条件。
案例:将上面的案例改为需同时满足勾选状态和勾选内容为C时才会触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <Style TargetType="CheckBox"> <Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsChecked" Value="true"/> <Condition Property="Content" Value="B"/> </MultiTrigger.Conditions> <MultiTrigger.Setters> <Setter Property="FontSize" Value="20"/> <Setter Property="Foreground" Value="Orange"/> </MultiTrigger.Setters> </MultiTrigger> </Style.Triggers> </Style>
|

DataTrigger
DataTrigger对象的Binding属性会把数据源送进来,一旦送来的值与Value属性一致,则触发。
案例:TextBox的Text长度小于7,Border保持红色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <Window x:Class="WpfApplication1.Window42" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window42" Height="184" Width="324"> <Window.Resources> <local:L2BConverter x:Key="cbtr"></local:L2BConverter> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource cbtr}}" Value="false"> <Setter Property="BorderBrush" Value="Red"></Setter> <Setter Property="BorderThickness" Value="1"></Setter> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <TextBox Margin="5"></TextBox> <TextBox Margin="5,0"></TextBox> <TextBox Margin="5"></TextBox> </StackPanel> </Window>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class L2BConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int textLength = (int)value; return textLength > 6 ? true : false; }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
|
数据源使用了RelativeSource,如果不明确指出Source的值,Binding会把控件的DataContext属性作为数据源而不是把控件自身作为数据源。我们关注的字符串的长度,如何基于长度进行判断就要使用到了Converter。

MultiDataTrigger
多个数据同时满足时才能触发。
案例:界面上使用ListBox显示一列Student数据,当Student对象同时满足Id为2,Name为Darren的时候高亮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <Window x:Class="WpfApplication1.Window43" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window43" Height="262" Width="425"> <Window.Resources> <Style TargetType="ListBoxItem"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Id}" Width="60"></TextBlock> <TextBlock Text="{Binding Name}" Width="120"></TextBlock> <TextBlock Text="{Binding Skill}" Width="60"></TextBlock> </StackPanel> </DataTemplate> </Setter.Value> </Setter> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=Id}" Value="2"></Condition> <Condition Binding="{Binding Path=Name}" Value="Darren"></Condition> </MultiDataTrigger.Conditions> <MultiDataTrigger.Setters> <Setter Property="Background" Value="Orange"></Setter> </MultiDataTrigger.Setters> </MultiDataTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <ListBox x:Name="lbInfos" Margin="5"></ListBox> </StackPanel> </Window>
|
1 2 3 4 5 6 7 8 9 10 11
| private void InitialInfo() { List<Student38> infos = new List<Student38>() { new Student38(){ Id=1, Name="Tom", Skill="Java"}, new Student38(){ Id=2, Name="Darren", Skill="WPF"}, new Student38(){ Id=3, Name="Jacky", Skill="Asp.net"}, new Student38(){ Id=2, Name="Andy", Skill="C#"}, }; this.lbInfos.ItemsSource = infos; }
|

EventTrigger
EventTrigger是最特殊的一个,它不是由属性值或者数据变化来触发,而是由事件来触发。其次,被触发后它并非应用一组Setter,而是执行一段动画,因此UI层的动画往往用EventTrigger来触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <Window x:Class="WpfApplication1.Window44" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window44" Height="258" Width="321"> <Window.Resources> <Style TargetType="Button"> <Style.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Width"></DoubleAnimation> <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Height"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Width"></DoubleAnimation> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Width="40" Height="40" Content="OK"></Button> </Grid> </Window>
|

触发器并非只能用在Style中,各种Template也可以拥有自己的触发器。