WPF(触发器)

使用触发器,可以动态地更改控件的外观,因为一些事件或属性值改变了。通常这都必须在代码中实现,使用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。 

posted @ 2022-04-12 22:46  Bridgebug  阅读(157)  评论(0编辑  收藏  举报