使用触发器,可以动态地更改控件的外观,因为一些事件或属性值改变了。通常这都必须在代码中实现,使用WPF,也可以用XAML实现,而这只会影响UI。
1.属性触发器
属性触发器在属性值改变时激活。Style类有一个Triggers属性,通过它可以指定属性触发器。
<Window x:Class="WpfAppLearn1.Window4"
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:WpfAppLearn1"
mc:Ignorable="d" Title="Window4" Height="450" Width="800">
<Canvas HorizontalAlignment="Left" Height="281" VerticalAlignment="Top" Width="679">
<Canvas.Resources>
<Style x:Key="tbStyle1" TargetType="TextBox">
<Setter Property="Background" Value="Aqua" />
<Setter Property="Foreground" Value="Chocolate" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="AliceBlue" />
<Setter Property="Text" Value="Hello" />
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
<TextBox Style="{StaticResource tbStyle1}" Height="23" Width="120" Canvas.Left="175" Canvas.Top="107" />
</Canvas>
</Window>
上述代码,当鼠标移入TextBox时,将背景色改为AliceBlue,文本改为Hello。当 鼠标移出TextBox时,样式会恢复本来的效果,这里就会将背景色重新设置为Aqua,文本变为空。
PS:触发器触发时要修改的值若不是控件的默认值,就必须在样式中定义,否则触发没效果。
<TextBox Style="{StaticResource tbStyle1}" Background="Beige" Height="23" Width="120" />
若是直接给TextBox定义背景色,当触发器激活时,并不会改变控件的背景色,文本效果还是可以触发的,若是直接定义文本不为TextBox(TextBox的Text默认值为TextBox)时也不会达到效果。
2.多触发器
属性的值变化时,就会激活属性触发器,如果因为两个或多个属性同时改变时激活触发器,就可以使用MultiTrigger。
<Window x:Class="WpfAppLearn1.Window4"
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:WpfAppLearn1"
mc:Ignorable="d"
Title="Window4" Height="450" Width="800">
<Canvas HorizontalAlignment="Left" Height="281" VerticalAlignment="Top" Width="679">
<Canvas.Resources>
<Style x:Key="tbStyle1" TargetType="TextBox">
<Setter Property="Background" Value="Aqua" />
<Setter Property="Foreground" Value="Chocolate" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Text" Value="123" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Red" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
<TextBox Style="{StaticResource tbStyle1}" Height="23" Width="120" Canvas.Left="175" Canvas.Top="107" />
</Canvas>
</Window>
上述代码,当鼠标移入TextBox且Text为123时激活触发器。
触发器就相当于事件,也区分订阅的顺序,当激活时按住订阅的顺序依次触发。下述代码当鼠标移入且Text为123时的背景色并不是Yellow,而是AliceBlue。
<Window x:Class="WpfAppLearn1.Window4"
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:WpfAppLearn1"
mc:Ignorable="d"
Title="Window4" Height="450" Width="800">
<Canvas HorizontalAlignment="Left" Height="281" VerticalAlignment="Top" Width="679">
<Canvas.Resources>
<Style x:Key="tbStyle1" TargetType="TextBox">
<Setter Property="Background" Value="Aqua" />
<Setter Property="Foreground" Value="Chocolate" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Text" Value="123" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Red" />
</MultiTrigger.Setters>
</MultiTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="AliceBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
<TextBox Style="{StaticResource tbStyle1}" Height="23" Width="120" Canvas.Left="175" Canvas.Top="107" />
</Canvas>
</Window>
3.事件触发器
除了使用属性触发器之外,还可以定义一个事件触发器,来启动动画。属性触发器在属性改变其值时激活,事件触发器在事件发生时激活。控件存在的事件都有对应的事件触发器。
<Window x:Class="WpfAppLearn1.Window3"
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:WpfAppLearn1"
mc:Ignorable="d" Title="Window3" Height="206" Width="509" WindowStartupLocation="CenterScreen">
<Canvas x:Name="canvas1" Background="#FFCFC9C9" Margin="0,0,1,0" Width="500">
<TextBox x:Name="tb1" Height="23" TextWrapping="Wrap" Text="TextBox" Width="120" Canvas.Left="60" Canvas.Top="75">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="OrangeRed" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Canvas>
</Window>
上例定义一个一个鼠标移入控件时的事件触发器。有没有考虑过,如果订阅了一个鼠标移入事件的话,那时触发器先执行还是事件先执行呢???
private void tb1_MouseEnter(object sender, MouseEventArgs e)
{
this.tb1.Background = new SolidColorBrush(Colors.Blue);
}
结果表明,事件会是最后触发的,触发顺序:事件触发器 -> 属性触发器 -> 事件
4.数据触发器
如果绑定到控件上的数据满足指定条件,就激活数据触发器。
public class Book
{
public string Title { get; set; }
public string Publisher { get; set; }
public string Isbn { get; set; }
public override string ToString()
{
return $"{Title},{Publisher},{Isbn}";
}
}
<Window x:Class="WpfAppLearn2.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:WpfAppLearn2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="319" Background="#FFD4D2D2" WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:Book x:Key="theBook" Title="C#" Publisher="MS" Isbn="123456"/>
</Window.Resources>
<Canvas DataContext="{StaticResource theBook}" HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.Resources>
<Style x:Key="tbStyle" TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Title}" Value="C#4.0">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
<TextBox Height="23" Style="{StaticResource tbStyle}" Text="{Binding Title}" Width="120" Canvas.Left="65" Canvas.Top="235"/>
<TextBox Height="23" Style="{StaticResource tbStyle}" Text="{Binding Title}" Width="120" Canvas.Left="65" Canvas.Top="195"/>
</Canvas>
</Window>
其中两个TextBox控件的Text属性都是绑定了Title属性,所以当其中一个TextBox的Text属性值发生改变时也会影响另一个TextBox。而数据触发器是根据绑定的数据来判断是否激活,所以当其中一个Text改为C#4.0,并确定修改,更新到Title属性中后,两个TextBox的前景色都会改为Red。