WPF触发器(非数据库中的触发器)

一、什么是触发器?触发器(Trigger)就是当某种条件满足后即完成相应逻辑功能的一部分程序组成。在当前的WPF中,Trigger一共有三种类型,它们分别是:

(1)属性触发器:其对应的类是Trigger。它在特定关联属性发生变化时被触发。

(2)数据触发器:其对应的类是DataTrigger。它在特定的CLR类型所记录的值发生变化时被触发。

(3)事件触发器:其对应的类是EventTrigger。它将在特定的路由事件发生时被触发。

在WPF中,每一个可以使用触发器的类中都会有一个Triggers属性。拥有这个属性的类有:FrameworkElement,Style,DataTemplate和ControlTemplate。

注意:FrameworkElement类只支持EventTrigger。这是因为微软还没有完成它对其他两类触发器的支持。

如果程序中需要使用属性触发器或数据触发器的功能,软件开发人员就需要使用设置样式触发器的方法对触发器进行一次包装,再将该样式应用在FrameworkElement类的实例上。因此就现在来说,Trigger和EventTrigger仅可以用在控件模板或样式中,而DataTrigger则只能用在数据模板之中。同时,为了支持对复杂触发条件的表示,WPF还引入了MultiTrigger和MultiDataTrigger完成对与逻辑的支持。如果想用触发器表示逻辑,软件开发人员可以通过将多个触发器同时放置到Triggers属性中完成。

二、触发器使用准则

不论是上面的哪种触发器,都不能脱离WPF对用户界面进行定义的三个准则。而这三个准则不仅导致触发器成为了WPF的一部分,更重要的是,还完成了对触发器使用规范的定义。

(1)元素合成

常用的,指定targetType.比如将触发源定义为Button类实例的好处是:软件在处理Button类实例的鼠标左键消息的同时也就处理了Image类实例的鼠标左键消息。元素合成对触发器使用的影响不仅如此。实际上WPF中的各个控件都是由其他界面元素组成的,比如组成按钮控件的Border,ButtonChrome等。那么在使用XAML定义一个控件的外观,也就是该控件的ControlTemplate的时候,软件开发人员就需要考虑触发器消息源的位置。

(2)界面与行为分离

一个界面上的功能,而与后台程序的业务逻辑完全没有关系。因此软件开发人员需要在XAML中使用一种方法完成该功能。这个方法就是使用触发器。

(3)选择合适的触发条件

在WPF中,用户可以发现许多貌似重复的事件以及函数。比如IInputElement接口已经实现了表示鼠标左键点击的MouseLeftButtonDown事件,而在ButtonBase类中WPF又为相同行为添加了Click事件。该事件不仅表示点击鼠标左键导致的按钮被按下这一行为,也表示默认按钮在用户按下回车键时被按下或当前具有输入焦点的按钮在用户按下空格键时被按下这一行为。另外一个例子是TextBox类不仅有GotFocus这一事件,更有GotKeyboardFocus,GotStylusCapture和GotMouseCapture等事件。也就是说,Click事件以及GotFocus事件都是具有更强大功能的事件,而且可以预计的是,各种WPF控件中还有许多这样的类似情况。因此在XAML中定义触发器的时候,软件开发人员一定要考虑清楚触发器的实际触发条件。

三、触发器类的继承结构

TriggerBase类是一个虚基类。该类直接派生自DependencyObject类,并只引入了两个新的属性:EnterActions和ExitActions。这两个属性分别表示所侦听的属性触发当前触发器时以及离开触发状态时所要执行的动作。但是,由于EventTrigger表示发生事件的一个时间点,而并不是保持在某一种状态的一段时间,所以EventTrigger并不支持对该属性的使用。为了赋予EventTrigger相同的功能,WPF为它添加了Actions属性。

示例:

        <Style x:Key="ButonStyle" TargetType="Button">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.25" Duration="0:0:1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>

上面这段样式表示,当鼠标移上的时候,Button变得不透明,离开后又逐渐恢复原样。

四、Setter类的使用

Setter类是非常容易使用的。它具有三个常用的属性:TargetName,Property和Value。这三个属性分别表示需要设置属性所在实例的名称、需要进行设置的属性和需要将该属性设置的值。但需要注意的是,被设置的属性必须是关联属性。当Trigger或Style中设置了TargetType的时候,XAML可以直接指定需要设置的属性而省略对象的类型。但在没有指定TargetType的情况下,Setter中对TargetType类型的Property属性的设置就必须使用TargetType.Property的形式。例如,当需要使用Setter元素设置按钮控件的背景颜色为蓝色时,软件开发人员就可以使用下面的XAML语句:

<Setter Property="Button.Background" Value="Blue"/> 
从MSDN对Setter类的基类SetterBase的介绍中可以看到,Setter类的基类SetterBase不只有一个派生类。除了Setter类之外,SetterBase类的派生类还有一个EventSetter类。EventSetter类用来完成对事件处理函数的定义。例如,若想让一个Button类实例在鼠标移动到其上时运行OnMouseEnter函数,软件开发人员就可以使用下面的代码:
<EventSetter Event="Button.MouseEnter" Handler="OnMouseEnter"/>

EventSetter无疑是一个不太友好的设计。而且在不同地方使用不同的EventSetter的情况下,软件开发人员并没有一个好的办法判断各个事件处理函数被执行的先后次序。而在一个以事件作为驱动的程序中,无法对事件响应函数的执行顺序进行控制无疑是一件最危险的事情。

五、各种触发器的使用

1.属性触发器

首先来看看属性触发器。属性触发器在指定的属性具有指定的值时,执行它所包含的一系列Setter完成对其他属性的设置。而当该属性不再是该指定值时,所有的属性设置将被恢复到前一状态。

样式:        <Style x:Key="TextBoxStyle1" TargetType="TextBlock">
            <Style.Triggers>
                    <Trigger Property="Text" Value="text">
                        <Setter Property="Background" Value="Aqua"/>
                    </Trigger>
            </Style.Triggers>
        </Style>

应用:
         <TextBlock Width="50" Style="{StaticResource TextBoxStyle1}" Text="text">
         </TextBlock>

在包含上例代码的程序中,如果用户在文本输入框中输入"text",输入框的背景颜色将变成绿色。完成这种控制逻辑的就是在Style中定义的属性触发器Trigger。在Trigger的声明中,对Trigger各属性的设置声明了Trigger被触发的条件:当Text属性为字符串"text"的时候,执行Setter中对属性的设置,即将背景颜色变成绿色。

4.数据触发器

除了Trigger类可以用来侦听属性的变化外,软件开发人员还可以使用DataTrigger完成对任意类型的CLR数据变化的侦听。因此,DataTrigger类不仅可以完成Trigger类的所有功能,更可以运行非关联属性的更改触发逻辑。DataTrigger类一共引入了三个参数:Binding,Value和Setters。当需要设置数据触发器侦听的数据源时,软件开发人员应该以通过绑定对Binding属性赋值的方式来完成。即如果需要使用DataTrigger完成上面对TextBox背景颜色进行更改的功能。

        <Style x:Key="TextBoxStyle2" TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="123">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

需要注意的是:虽然软件开发人员可以使用DataTrigger完成对任意CLR类型数据变化的侦听,但Setter只能对关联属性进行设置。并且XAML不能在Setter中对Style属性进行更改。其原因是:触发器可以在样式中进行定义。当一个在样式中定义的触发器更改了其所在实例的样式时,WPF怎么继续处理触发器中剩余的设置?为了避免这个问题,WPF禁止在触发器中对样式进行设置。

5.事件触发器

WPF中还提供另一种触发器。该触发器的触发条件就是一个事件的发生。该触发器所对应的类为EventTrigger,即事件触发器。该类从TriggerBase类派生后只添加了三个属性:Actions,RoutedEvent和SourceName。软件开发人员可以通过SourceName属性指定激活该触发器的元素名称。而RoutedEvent属性则记录激活该触发器的事件。Actions是一个只读属性,表示触发器被触发时需要执行的动作。

                <EventTrigger RoutedEvent="Mouse.MouseEnter">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                          Duration="0:0:0.2"
                                          Storyboard.TargetProperty="Width"
                                          To="65"  />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>

6.或逻辑触发器

当需要表示或逻辑关系时,软件开发人员可以简单地将多个触发器并列。当某一个触发器所标识的条件满足时,该触发器所包含的行为将执行,导致使用这个触发器的用户界面元素实例的属性改变。如果在前面的例子中,软件设计师不仅希望TextBox 的背景颜色在用户输入为"text"时为绿,也希望背景在用户输入为"text."时为绿,示例如下:

<TextBox TextWrapping="Wrap" Margin="5">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}"Value="text">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="text.">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

在或逻辑关系中,触发器的各属性匹配可能在同一时间被满足。在这种情况下,触发器对状态的设置同时生效。在各个触发器对属性的设置发生冲突时,WPF将按照后声明的触发器所制定的规则对属性进行设置。如下:

<Button Content="Press Me!">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Button.Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

当用户将鼠标移动到按钮上面并使用左键对按钮进行点击的时候,按钮的颜色将是红色,而不是蓝色。因为在按钮被按下之前,IsMouseOver属性的值为True,而在按钮被按下时IsPressed属性的值也变为True,所以按照后声明优先的决定方式,WPF将设置该按钮的背景颜色为红色。

7.与逻辑触发器

如果要表示与逻辑关系,软件开发人员就需要使用MutiTrigger或MutiDataTrigger。在使用这两种触发器时,软件开发人员需要向它们的Conditions集合中添加触发条件。假设软件需要下面一种功能:当TextBox中所记录的字符串是"text"并且鼠标在TextBox之上时,TextBox的背景颜色将变成绿色。示例如下:

<TextBox TextWrapping="Wrap" Margin="5">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Text" Value="text"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="Aqua"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
时间: 2024-08-25 03:52:04

WPF触发器(非数据库中的触发器)的相关文章

浅谈数据库中的触发器

触发器 其是一种特殊的存储过程.一般的存储过程是通过存储过程名直接调用,而触发器主要是 通过事件(增.删.改)进行触发而被执行的.其在表中数据发生变化时自动强制执行. 常见的触发器有两种:after(for).instead of,用于insert.update.delete事件. after(for)        表示执行代码后,执行触发器 instead of        表示执行代码前,用已经写好的触发器代替你的操作 触发器语法: create trigger 触发器的名字   on

查看数据库中存在触发器的表

这次在项目中,我们为了做数据库同步,采用了触发器机制,为数据库做迁移时,我们需要获取数据库中那些表使用了触发器,方便制作数据库安装包. 构思: 触发器在MSSQL作为一个对象进行管理,那么我们就可以通过sysobjects表进行查询获取,所以我们就编写了一下触发器获取SQL SELECT object_name(a.parent_obj) as [表] ,a.name as [触发器] ,(case when b.is_disabled=0 then '使用中' else '停用' end) a

Oracle使用触发器和mysql中使用触发器的比较——学习笔记

一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志,自动通知好友,其实就是在增加日志的时候做一个出发,再向表中写入条目. --触发器的效率很高 举例:论坛的发帖,每插入一个帖子都希望将版面表中的最后发帖时间,帖子总数字段进行同步更新,这时使用触发器效率会很高. 二.Oracle 使用 PL/SQL 编写触发器 1.--PL/SQL创建触发器的一般语法

数据库中的触发器,索引 ,事务

一.触发器 触发器是一种实施复杂数据完整性的特殊存储过程,在对表或视图执行update.insert或delete语句时自动触发执行,以防止对数据进行不正确.未授权或不一致的参数. /*创建update触发器*/ create trigger [dbo].[TaocanType_update] on [dbo].[Table_TaocanType] for update  as update [dbo].[Table_ChoseTaocanType] set Taocan=inserted.Ta

sql-server数据库中利用触发器实现表与表之间的级联删除

create trigger Delete_Student --创建一个触发器 on student instead of delete as declare @sno varchar(20) select @sno= sno from deleted delete from score where sno=@sno delete from student where sno=@sno go delete from Student where Sno='101' select *from Stu

MySQL数据库中的触发器

--触发器是一类特殊的监控增删改操作,并产生相应的增删改的操作 --1,监视谁 2,监视动作 3,监视时间(之前或之后) 4,触发的事件 --触发器的简单语法 create trigger 触发器名字 after/before(触发时间) insert/delete/update(监视事件) on 表名 (监视地址) for each row begin sql语句; end; --因为一条sql语句只能有一个边界符,所以上面语句会发生错误,用delimiter $ --将边界符改为$ 这样就不

WPF如何将数据库中的二进制图片数据显示在Image控件上

首先在xaml文件里定义一个Image控件,取名为img MemoryStream stream = new MemoryStream(获得的数据库对象): BitMapImage bmp = new BitMapImage(); bmp.BeginInit();//初始化 bmp.StreamSource = stream;//设置源 bmp.EndInit();//初始化结束 img.Source = bmp;//设置图像Source 很多人用这个方法都没有初始化BitMapImage ,这

数据库中的相关术语

在Oracle数据库中每个数据库里面都包含很多对象,主要包括表.视图.存储过程.触发器及其约束. 1.表 表,即在数据库中存放数据用的数据表.每一个数据库中都可以包含很多张数据表,但是每一个数据表的名字都是不能重复的.表的每一行代表一条记录,每一列都有一个列名,列名时唯一的,行与列的交叉点称为字段. 2.视图 视图是数据库的虚拟表.在视图中存放的是从数据库表中查询 的记录,使用视图主要是为了方便信息查询,同时也能缩短查询数据的时间. 3.存储过程 存储过程是由SQL 语句和控制流语句组成的代码块

数据库中触发器的创建与注意事项

[IT专家网独家] 触发器是特殊的存储过程,但它的执行不是由手工调用,也不是由程序执行,触发器必须由事件才能触发.触发器的触发事件分可为3类,分别是DML事件.DDL事件和数据库事件. DML触发器的要点 DML触发器是定义在表上的触发器,由DML事件引发.编写DML触发器的要素是: 确定触发的表,即在其上定义触发器的表. 确定触发的事件,DML触发器的触发事件有INSERT.UPDATE和DELETE三种 确定触发时间.触发的时间有BEFORE和AFTER两种,分别表示触发动作发生在DML语句