最近做的Silverlight项目上用到了大量的拖拽,自动跟随等功能,由于赶时间,加上对Silverlight半生不熟,用的是最简单也是最不好维护的方法。项目忙完了闲下来,想重构一下代码,想起了Trigger和Action这两个东西,当初接触这两个东西不深,只是认识,不知道用。现在正好可以好好学习一下,参考了重多大神的代码之后,终于初步熟悉了它们。这里分享一下我对Trigger和Action的认识。

我用一个最简单的例子来说明Action与Trigger,点击一个Button弹出MessageBox。

建立一个Silverlight Application,引用System.Windows.Interactivity.dll程序集(这个程序集很重要,是使用Trigger,Action,Behavior必须引用的)。我们在MainPage里放一个Button并给一个Click事件。

xaml代码如下:

   1: <UserControl x:Class="SilverlightApplication1.MainPage"

   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   6:     mc:Ignorable="d"

   7:     d:DesignHeight="300" d:DesignWidth="400">

   8:  

   9:     <Grid x:Name="LayoutRoot" Background="White">

  10:         <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />

  11:     </Grid>

  12: </UserControl>

cs代码如下:

   1: public partial class MainPage : UserControl

   2: {

   3:     public MainPage()

   4:     {

   5:         InitializeComponent();

   6:     }

   7:  

   8:     private void button1_Click(object sender, RoutedEventArgs e)

   9:     {

  10:         MessageBox.Show("Hello World!");

  11:     }

  12: }

很简单,这是最传统的做法。

下面Action要上场了。所谓Action,就是去执行某些操作。可以根据需要创建自己的Action,常见的需要创建Action的情况有:改变属性、调用方法、打开窗口、导航到某个页面、设置焦点等。自定义Action可从 TriggerAction<DependencyObject>TargetedTriggerAction<DependencyObject>继承,区别在于操作对象是关联对象还是特定的目标对象,实现时覆盖Invoke方法即可。我们新建一个简单的Action,代码如下:

   1: public class Action1 : TriggerAction<DependencyObject>

   2: {

   3:     public Action1()

   4:     {

   5:         

   6:     }

   7:  

   8:     protected override void Invoke(object o)

   9:     {

  10:         MessageBox.Show("Hello World! This message comes from an action.");

  11:     }

  12: }

在Invoke方法里Show一个MessageBox。这样,一个Action这创建好了。如何使用它呢?看下面的代码。

xaml代码:

   1: <UserControl x:Class="SilverlightApplication1.MainPage"

   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   6:     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

   7:     xmlns:local="clr-namespace:SilverlightApplication1"

   8:     mc:Ignorable="d"

   9:     d:DesignHeight="300" d:DesignWidth="400">

  10:  

  11:     <Grid x:Name="LayoutRoot" Background="White">

  12:         <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">

  13:             <i:Interaction.Triggers>

  14:                 <i:EventTrigger EventName="Click">

  15:                     <local:Action1 />

  16:                 </i:EventTrigger>

  17:             </i:Interaction.Triggers>

  18:         </Button>

  19:     </Grid>

  20: </UserControl>

运行结果如图:

很显然,Button的单击调用了那个Action,Button不再去触发xaml.cs里的那个事件处理方法了,而了触发了之前新建的Action1。回到xaml代码,EventTrigger是Silverlight自带的一个触发器(Trigger)。Trigger一量触发,就会执行对应的Action。这里我们把Action1与EventTrigger关联到一起(“关联”这个词可能用得不合适,反正就这个意思),EventTrigger触发Click事件,执行Action弹出MessageBox。而xaml.cs文件里的代码不再需要了。它的好处是不是已经看出来了?有效的分离了UI与后台代码。

下面Trigger正式登场。所谓Trigger,就是监听某些条件的变化,比如事件触发,属性值改变等,进而触发一些动作的发生。这些Triggers可能是EventTrigger、CollisionTrigger 等,当然更多的或许是创建自己的Trigger。自定义Trigger只需要从TriggerBase<DependencyObject>继承,并覆盖OnAttached和OnDetaching方法即可。我面来创建一个Trigger。代码如下:

   1: public class Trigger1 : TriggerBase<Button>

   2: {

   3:     protected override void OnAttached()

   4:     {

   5:         base.OnAttached();

   6:         this.AssociatedObject.Click += new RoutedEventHandler(Trigger1_Click);

   7:     }

   8:  

   9:     protected override void OnDetaching()

  10:     {

  11:         base.OnDetaching();

  12:         this.AssociatedObject.Click -= new RoutedEventHandler(Trigger1_Click);

  13:     }

  14:  

  15:     protected void Trigger1_Click(object sender, RoutedEventArgs e)

  16:     {

  17:         MessageBox.Show("Hello World! This message comes from a trigger.");

  18:     }

  19: }

代码中我们用到了AssociationObject这个属性,这个属性表示绑定Trigger的对象,这里是一个Button,OnAttached中注册一个Click事件处理方法,OnDetching中取消注册(如果不取消注册,当这个Button上其它触发器触发时,这个触发器的效果还会重现,因为Click触发之后委托链上所有注册方法都会执行, 具体情况具体分析是否需要取消注册)。

在Xaml中这样来使用这个Trigger:

   1: <Grid x:Name="LayoutRoot" Background="White">

   2:     <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">

   3:         <i:Interaction.Triggers>

   4:             <local:Trigger1 />

   5:         </i:Interaction.Triggers>

   6:     </Button>

   7: </Grid>

运行如果如下:

这里Trigger1被触发了。

其实,触发器(Trigger)和动作(Action)是协同工作的。当某事件发生的时候,Trigger就会触发并调用一个Action,Trigger和Action组成了最简单的行为(Behavior下次再讨论)表现形式。

最后,我们让Trigger1和Action1协同工作一下。Trigger1的代码改一改:

   1: public class Trigger1 : TriggerBase<Button>

   2: {

   3:     protected override void OnAttached()

   4:     {

   5:         base.OnAttached();

   6:         this.AssociatedObject.Click += new RoutedEventHandler(Trigger1_Click);

   7:     }

   8:  

   9:     protected override void OnDetaching()

  10:     {

  11:         base.OnDetaching();

  12:         this.AssociatedObject.Click -= new RoutedEventHandler(Trigger1_Click);

  13:     }

  14:  

  15:     protected void Trigger1_Click(object sender, RoutedEventArgs e)

  16:     {

  17:         InvokeActions(null);

  18:     }

  19: }

Trigger1_Click方法里调用InvokeActions来执行“关联”到这个Trigger上的Action。Xaml如下:

   1: <Grid x:Name="LayoutRoot" Background="White">

   2:     <Button Content="Button" HorizontalAlignment="Left" Margin="35,31,0,0" Name="button1" VerticalAlignment="Top">

   3:         <i:Interaction.Triggers>

   4:             <local:Trigger1>

   5:                 <local:Action1 />

   6:             </local:Trigger1>

   7:         </i:Interaction.Triggers>

   8:     </Button>

   9: </Grid>

运行结果如下:

这里,Button绑定了Trigger1,Attach这个Trigger1时把Click事件注册上(OnAttached方法。关于Attach,请参考“附加属性”),所以单击Button就调用了绑定在Trigger1上的Action1。

至于这两个东西的好处就不必多说了,分离了UI与代码,提高了代码的复用。

好了,初学Trigger和Action,大致缕了一下它们之间的关系,就简单介绍到这,欢迎一起讨论。更神奇的Behavior将在下篇中介绍

附上上面的源代码

 
 
分类: Silverlight

【WPF】Silverlight中的Action与Trigger的更多相关文章

  1. WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示

    原文:WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示 为方便描述, 这里仅以正方形来做演示, 其他图形从略. 运行时效果图:XAML代码:// Transform.XAML< ...

  2. WPF/Silverlight中的RichTextBox总结

    WPF/Silverlight中的RichTextBox总结   在WPF或者是在Silverlight中有个非常强大的可以编辑的容器控件RichTextBox,有的时间会采取该控件来作为编辑控件.鉴 ...

  3. WPF,SilverLight中直线的样式示例

    原文:WPF,SilverLight中直线的样式示例 XAML代码:// LineStyle.xaml<Viewbox Width="600" Height="50 ...

  4. WPF/Silverlight Template使用及总结(转)

    WPF/Silverlight 中的控件都有Style和Template两种属性.前者解释为样式,是用来改变控件原有属性的,比如 Button 控件的(Width,Height,Background ...

  5. WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性

    原文 WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性 如果您在使用WPF/Silverlight进行相关动画开发中使用了Storyboard,并对关联属性进 ...

  6. WPF/Silverlight深度解决方案:(七)HLSL自定义渲染特效之完美攻略(中)

    原文:WPF/Silverlight深度解决方案:(七)HLSL自定义渲染特效之完美攻略(中) 通过上一节的解说,大家是否已经对HLSL有了较深刻的认识和理解,HLSL的渲染不仅仅局限于静态处理,通过 ...

  7. WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)

    一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...

  8. 三、Silverlight中使用MVVM(三)——进阶

    这篇主要引申出Command结合MVVM模式在应用程序中的使用 我们要做出的效果是这样的 就是提供了一个简单的查询功能将结果绑定到DataGrid中,在前面的基础上,这个部分相对比较容易实现了 我们在 ...

  9. 浅谈WPF本质中的数据和行为

    WPF缩写为Windows Presentation Foundation的缩写,本文所要谈的就是WPF本质中的数据和行为,希望通过本文能对大家了解WPF本质有所帮助. 如果自己来做一个UI框架,我们 ...

随机推荐

  1. Failed to set session cookie. Maybe you are using HTTP instead of HTTPS to access phpMyAdmin.

    原因:使用负载均衡的时候,第一次请求phpMyAdmin主页的时候web01进行处理,页面返回的cookie存放在web01上.填写用户名密码提交之后,是web02进行处理的,此时给页面的cookie ...

  2. topcoder srm 703 div1 -3

    1.给出一个包含$n$个元素的数组$x$,构造出一个有向无环图满足从节点$i$出发可以访问到的节点数为$x_{i}$. 思路:按照$x$从小到大排序.然后从前向后处理,当前节点依次与前面已经处理的节点 ...

  3. 对应web的常用flutter应用

    例如,创建一个Text widget: new Text('Hello World', style: new TextStyle(fontSize: 32.0)) 创建一个 Image widget: ...

  4. 【BZOJ4872】分手是祝愿

    分手是祝愿 [题目大意] 有n 个灯,每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被 ...

  5. bzoj2152: 聪聪可可 点分治

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2152 luogu爆搜都能过,总时间超过100ms就是写错了 思路 直接mod上面跑点分治就行 ...

  6. UVA 10318 Security Panel(DFS剪枝 + 状压 + 思维)题解

    题意:给一个r*c的矩阵开关(初始全打开的),每次按下一个开关都会改变3*3范围内的有*的地方的状态,问你最少几步能让开关全闭上,按升序输出按哪些按钮 思路:每个按钮至多按一下,按按钮的顺序和结果无关 ...

  7. leetcode 04 Median of Two Sorted Arrays

    n1 为 num1的 len n2 为 num2的 len 故中间的数应该是 k = (n1 + n2 + 1) / 2 二分 num1中位置 m1 , 故 num2的位置为m2 必须保证 nums1 ...

  8. P4363 [九省联考2018]一双木棋chess

    思路 容易发现只能在轮廓线的拐点处落子,所以棋盘的状态可以用一个n+m长度的二进制数表示 转移就是10变成01 代码 #include <cstdio> #include <algo ...

  9. (zhuan) 一些RL的文献(及笔记)

    一些RL的文献(及笔记) copy from: https://zhuanlan.zhihu.com/p/25770890  Introductions Introduction to reinfor ...

  10. AtomicReference实现单例模式

    CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试. 乐观锁的一种实 ...