WPF触发器总结

WPF触发器分类(一起学习WPF)

首先说明一点就是触发器可以完成的事情完全可以通过转换器或者直接编写代码进行实现,但是我更喜欢使用触发器,愿意很简单,实现更加直观,更符合MVVM,界面样式的变化不需要代码的过多接入。

WPF的触发器使用起来其实比较简单,但是却可以发挥很大的作用,使用得当可以使得22代码简洁,思路清晰。

使用触发器,可以自动完成简单的样式改变。

触发器可以分为以下五类:

1、Trigger简单触发器

最简单,也是最基础的触发器,可以检测依赖属性的变化,然后根据setter中设置的样式进行改变。

下边给出一个例子,我们创建一个Border,然后使用简单触发器,使当鼠标进入到Border时,显示一个红色的边框。

下边给出两个写法。

(1)第一种

 1 <Border Width="100" Height="30" BorderBrush="Blue" BorderThickness="3">
 2     <Border.Style>
 3         <Style TargetType="Border">
 4             <Style.Setters>
 5                 <Setter Property="Background" Value="Green"/>
 6             </Style.Setters>
 7             <Style.Triggers>
 8                 <Trigger Property="IsMouseOver" Value="True">
 9                     <Setter Property="BorderBrush" Value="Red"/>
10                     <Setter Property="BorderThickness" Value="3"/>
11                 </Trigger>
12             </Style.Triggers>
13         </Style>
14     </Border.Style> 
15 </Border>

(2)第二种

<Border Width="100" Height="30">
    <Border.Style>
        <Style TargetType="Border">
            <Style.Setters>
                <Setter Property="Background" Value="Green"/>
                <Setter Property="BorderBrush" Value="Blue"/>
                <Setter Property="BorderThickness" Value="3"/>
            </Style.Setters>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="3"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Border.Style> 
</Border>

对比两种写法,并经过尝试,发现第一种并没有起作用,运行后边框会一直显示最开始设置的值蓝色,而第二种写法会在鼠标移入时达到我们想要的效果,为什么会这样呢,这里我们引用WPF编程宝典中的一句话进行说明:

”本质上,触发器是众多覆盖从依赖属性返回的值的属性提供者之一。但原始的值(不管是本地设置还是通过样式设置)仍会保留。只要触发器被禁用,那么之前的属性值就会再次可用“。

这段话好像并不能解释前边抛出发问题,哈哈哈,不过这句话依旧很重要。

那么真正的原因是什么呢,我们在上边的代码中加入两个本地属性。

<Border Width="100" Height="30" BorderBrush="Orange" BorderThickness="3">
    <Border.Style>
        <Style TargetType="Border">
            <Style.Setters>
                <Setter Property="Background" Value="Green"/>
                <Setter Property="BorderBrush" Value="Blue"/>
                <Setter Property="BorderThickness" Value="3"/>
            </Style.Setters>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="3"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Border.Style> 
</Border>

运行起来会显示什么颜色呢,答案是会显示橙色。因为WPF允许在多个地方设置依赖属性的值,那么自然会涉及优先级的问题,也就是说本地属性的优先级要高于setter设置的值,而默认Style Setter的优先级又高于默认Style Trigger中设置的值,这种优先级别在所有的触发器中均适用。具体的优先级见下图,更为详细的关于依赖属性的说明会在专门的文章中进行说明。

最后需要说明一点的是,当有多个触发器设置同一个属性值的时候,触发器在标记中的排列顺序决定了最终显示的效果。比如我们在上边的例子中再增加一个IsVisible的触发器,设置同样的Setter,颜色为紫色,那么当鼠标移入Border后显示的边框显示的颜色将由Trigger在Triggers中的先后顺序决定。

2、MultiTrigger多条件触发器

多条件触发器其实就是普通触发器进行简单的组合,然后进行&&预算,当所有的条件满足后出发Setter中设置的属性,用一个简单的CheckBox进行说明。只有当控件处于可见状态并且选中时,复选框的边框呈现红色,这里只是举例,实际开发中必然是不会这样设置条件的。

<CheckBox>
    <CheckBox.Style>
        <Style TargetType="CheckBox">
            <Style.Setters>
                <Setter Property="BorderBrush" Value="Blue"/>
                <Setter Property="BorderThickness" Value="3"/>
            </Style.Setters>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsVisible" Value="True"/>
                        <Condition Property="IsChecked" Value="False"/>
                    </MultiTrigger.Conditions>
                    <MultiTrigger.Setters>
                        <Setter Property="BorderBrush" Value="Red"/>
                        <Setter Property="BorderThickness" Value="3"/>
                    </MultiTrigger.Setters>
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </CheckBox.Style>
</CheckBox>

3、DataTrigger数据触发器

数据触发器同样是和触发器一样,当达到设置的某个条件时,进行样式的更改,或者动画的触发。以及其他的一些操作,虽然目前并不知道还有哪些可以触发,哈哈哈。

使用方法一通百通,和普通触发器使用方法基本一样,先上例子。

<TextBox Margin="16 0 0 0" Width="80">
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Setters>
                <Setter Property="Foreground" Value="Green"/>                   
            </Style.Setters>
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=Text}" Value="5">
                   <Setter Property="Foreground" Value="OrangeRed"/>
                </DataTrigger>               
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

这个例子是在文本框中输入的值为“5”时将字体颜色设置为橙红色,其余时候为绿色。这里我们注意到数据触发器和前边的触发器出现了一个不同的地方,那就是绑定,(绑定我们在这里进行说明)出现了绑定就意味着这里的数据触发可以是多个条件,比如当我们绑定自身的某个属性值等于指定值的时候便可以实现部分触发器的功能,比如将例子中的Text属性替换为IsVisible,并将值设置为True,便能实现和前边一样的效果,当然这样做是不恰当的。除了绑定自身属性,还可以绑定其他元素的属性,使用ElementName进行绑定,或者我们干脆直接绑定后台的属性,并设置值,都可以实现数据触发器的效果。总结一些就是,依赖属性可以绑定的东西,均可以用作数据触发器的条件,前提是设置恰当的Value值。

4、MultiDataTrigger多数据触发器

这个触发器就不做过多的说明了,根据多条件触发器和数据触发器的学习,想必多条件数据触发器是非常好理解的,就是将几个是否相等的判断进行了且运算,如果全部成立,则触发效果,反之则无动于衷。

5、EventTrigger事件触发器

事件触发器和前边几个触发器相比是一个比较特殊的触发器,因为这个触发器的使用目的不是为了直接改变某个依赖属性的值,而是“缓慢”的改变,具有一个动画效果,用于触发故事板中的一段动画(动画我们放到这里学习)。更为官方的说法是事件触发器要求用户提供一系列修改控件的动作,这些动作通常被用于动画。

<Border Margin="16 0 0 0" Width="30" Background="OrangeRed">
    <Border.Style>
        <Style TargetType="Border">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetProperty="Width" From="30" To="100"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetProperty="Width" From="100" To="30"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
</Border>

这个事件触发器中,当鼠标移入后改变Border的长度,移除后恢复原来的长度。这里为什么会有两段动画呢,不是触发器不改变依赖属性原来的值,失效后自动恢复的嘛。这就是与属性触发器的不同了,如果希望元素返回原来的状态,需要反转事件触发器,这是因为默认的动画行为是一旦动画完成就继续保持激活状态,从而会继续保持动画结束时最后的属性值。

更为有意思的是,当依赖属性等于某个值的时候,也可以执行动画。也就是执行动画并不是事件触发器的专属,而是每种触发器都可以,为了使用这项技术,技巧是不为触发器提供任何的Setter对象,而是设置EnterActions和ExitActions属性,这两个属性都有一个动作集合,例如启动动画的BeginStorybord。当属性达到指定的值时,执行EnterActions,属性离开指定值时,执行EnterActions。

跟为详细的动画触发内容将会在后续的动画中进行记录学习。

说明:文中代码使用NET5进行编写。

 

posted @ 2022-03-09 21:56  IRisingStar  阅读(2877)  评论(0编辑  收藏  举报