深入浅出WPF-08.Event( 事件)02
路由事件
为了方便程序中对象之间的通信常常需要我们定义一些路由事件。使用路由事件比直接事件方便得多。
创建自定义路由事件的步骤:
1)声明并注册路由
2)为路由事件添加CLR事件包装
3)创建可以激发路由事件的方法
// 声明并注册路由事件
public static readonly RoutedEvent IOLSelectionChangedEvent = EventManager.RegisterRoutedEvent("IOLSelection", RoutingStrategy.Bubble, typeof(EventHandler<IOLSelectionEvnetArgs>), typeof(ReportPageBase));;
// 为路由事件添加CLR事件包装器
public event RoutedEventHandler IOLSelectionChanged
{
add { this.AddHandler(IOLSelectionChangedEvent, value); }
remove { this.RemoveHandler(IOLSelectionChangedEvent, value); }
}
// 激发路由事件的方法。
protected virtual void OnIOLSelectionChanged()
{
IOLSelectionEvnetArgs newEvent = new IOLSelectionEvnetArgs(IOLSelectionChangedEvent, this);
newEvent.Right = true;
this.RaiseEvent(newEvent);
}
public class IOLSelectionEvnetArgs : RoutedEventArgs
{
public IOLSelectionEvnetArgs(RoutedEvent routedEvent, object source)
: base(routedEvent, source)
{
}
public bool Right { set; get; }
}
public ReportView()
{
InitializeComponent();
this.DataContext = CurPatientStudyModel.CreateInstance();
this.AddHandler(ReportPageDataBase.IOLSelectionChangedEvent, new EventHandler<IOLSelectionEvnetArgs>(OnIOLSelectionChanged));
}
路由定义的手法和依赖项属性极其相似,使用EventManager的RegisterRoutedEvent方法进行注册。
为路由事件添加CLR事件包装是为了把路由事件暴露得像一个传统的直接事件,仍然可以使用操作符+=为事件增加处理器,使用-=操作符为事件移除处理器。
激发路由事件很简单,首先创建需要让事件携带的消息(RoutedEventArgs类的实例),并把它与路由事件关联,然后调用元素的RaiseEvent方法把事件送出去。这个激发与传统的事件激发不同,传统直接事件的激发是通过调用CLR事件的Invoke方法实现,而路由事件的激发与作为其包装器的CLR事件毫不相干。
创建路由事件方法RegisterRoutedEvent的四个参数:
1)string类型,路由事件的名称,建议和RoutedEvent变量的前缀和CLR事件包装器的名称一致。
2)路由事件的策略,Bubble(冒泡式):路由事件由事件的激发者出发向他的上级容器一层一层路由,直到最外层容器。Tunnel(隧道式):事件的路由方向正好和Bubble相反,是由UI树的树根向事件激发控件移动。Direct(直达式):模仿CLR直接事件,直接将事件消息送达到事件处理器。
3)指定事件处理器的类型。事件处理器的返回值类型和参数列表必须与此参数指定的委托保持一致。
4)指明路由事件的宿主类型。与依赖属性相似,这个类型和第一个参数共同参与底层算法产生这个路由事件的Hashcode,并注册到程序的路由事件列表中。
注意一下,RoutedEventArgs具有一个bool类型的属性Handled,一旦这个属性被设置为true,就表明路由事件已经被处理了,路由事件就不会继续传递下去。
RoutedEventArgs包含了路由事件的消息。RoutedEventArgs有两个属性Source和OriginalSource,这两个属性都表示路由事件传递的起点(路由事件的源头)。只不过Source表示的是LogicalTree上的消息源头,而OriginalSource表示的是VisualTree上的源头。一般我们只使用Source来使用叶子节点作为消息源头处理就满足条件了。
事件也是可以附加的,我们称为附加事件(Attached Event)。路由事件的宿主都是一些拥有可视化实体的界面元素,而附件事件则不具备显示在用户界面上的能力。也就是说,附加事件的宿主没有界面渲染功能。我们可以把路由事件定义在一个普通的类中,当这个类中的某个属性值发生变化时,激发一个路由事件,使用界面元素捕获这个事件。在界面元素中可以使用AddHandler和RemoveHandler来增加或者移除事件处理器。
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
// 声明并注册路由事件
public static readonly RoutedEvent NameChangedEvent = EventManager.RegisterRoutedEvent("NameChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Student));
// 为界面元素添加路由事件侦听
public static void AddNameChangedHandler(DependencyObject dobj, RoutedEventHandler h)
{
UIElement e = dobj as UIElement;
if (e != null)
{
e.AddHandler(Student.NameChangedEvent, h);
}
}
// 移除监听
public static void RemoveNameChangedHandler(DependencyObject dobj, RoutedEventHandler h)
{
UIElement e = dobj as UIElement;
if (e != null)
{
e.RemoveHandler(Student.NameChangedEvent, h);
}
}
}
public MainWindow()
{
InitializeComponent();
Student.AddNameChangedHandler(this,new RoutedEventHandler(NameChangedHandler));
}
private void NameChangedHandler(object sender, RoutedEventArgs e)
{
Console.WriteLine("NameChanged");
e.Handled = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Student stu = new Student() { Id = 1, Name = "liu" };
stu.Name = "li Test";
RoutedEventArgs arg = new RoutedEventArgs(Student.NameChangedEvent,stu);
this.RaiseEvent(arg);
}
如果一个非UIElement派生类注册了路由事件,这个类的实例既不能自己激发(Raise)此路由事件,也不能自己侦听此路由事件。只能把这个事件的激发附着在具有RaiseEvent方法的对象上,借助这个对象的RaiseEvent方法把事件发送出去,事件的侦听也只能交给别的对象去做。
深入浅出WPF-08.Event( 事件)02的更多相关文章
- 《深入浅出WPF》笔记——事件篇
如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...
- [转]深入浅出WPF(7)——数据的绿色通道,Binding
本文转自:http://liutiemeng.blog.51cto.com/120361/95273 小序: 怎么直接从2蹦到7啦?!啊哦,实在是不好意思,最近实在是太忙了,忙的原因也非常简单——自己 ...
- WPF的路由事件、冒泡事件、隧道事件(预览事件)
本文摘要: 1:什么是路由事件: 2:中断事件路由: 3:自定义路由事件: 4:为什么需要自定义路由事件: 5:什么是冒泡事件和预览事件(隧道事件): 1:什么是路由事件 WPF中的事件为路由事件,所 ...
- 深入浅出WPF(1)—转(http://liutiemeng.blog.51cto.com/120361/91631/)
深入浅出WPF(1)——什么是WPF 2008-05-15 19:06:00 小序: Hi,大家好!几乎两个月没有写技术文章了.这两个月,我在学习WPF.回顾一下两个月的学习历程,有两个感觉— ...
- 《深入浅出WPF》 学习笔记
<深入浅出WPF> 序言 1. 什么是WPF 2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...
- 【【分享】深入浅出WPF全系列教程及源码
】
因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...
- WPF 冒泡路由事件
在WPF中,例如,可以构建一个包含图形的按钮,创建一个具有文本和图片混合内容的标签,或者为了实现滚动或折叠的显示效果在一个特定的容器中放置内容.甚至可以多此重复嵌套,直到达到您所希望的层次深度. 这种 ...
- C# event 事件学习
C# event 事件学习 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-26 章节: 简单事件编写 模拟 WPF 控件传递 ...
- saltstack之salt event事件用法
event是一个本地的ZeroMQ PUB Interface,event是一个开放的系统,用于发送信息通知salt或其他的操作系统.每个event都有一个标签.事件标签允许快速制定过滤事件.除了标签 ...
- WPF中的事件及冒泡事件和隧道事件(预览事件)的区别
WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别 WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别 本文摘要: 1:什么是路由事件: 2:中断事件路 ...
随机推荐
- GIT基础篇,配置账号及命令查看以及帮助命令
提交用户名和邮件地址 1 安装完Git首先要设置你的用户名称与邮件地址.每一个Git的提交都会使用这些信息,并且它会写入到你的每一次提交中. 2 git config --global user. ...
- SpringBoot2.0整合Quartz定时任务(持久化到数据库,更为简单的方式)
1. pom文件添加依赖 <dependencies> <dependency> <groupId>org.springframework.boot</gro ...
- 十九:JDBC操作事务
二.MySQL数据库中操作事务命令 2.1.开启事务(start transaction) 使用"start transaction"开启MySQL数据库的事务,如下所示:
- Commons-Collections(二)之set
MultiSet set我们都知道,它是无序的,并且是不允许出现重复元素的.但有些场景我们不需要顺序,但是我们需要知道指定key出现的个数(比如每样产品ID对应的剩余数量这种统计信息),那么用Mult ...
- 关于Ubuntu18.04 linux系统使用搜狗输入法 出现乱码
解决: 执行下面的命令即可!无需重启系统 killall fcitx
- 传统JIT和java9新特性AOT理解
java慢的原因 1. 除了少量基本类型用栈存储外,所有对象都使用堆存储.堆的性能低于栈. 2. 很多强制类型转换(cast)或加查,耗用内存大.java运行时对类型检测,如果类型不正确会抛出Cl ...
- 初识cookie
package day01.cookies; import java.io.IOException; import java.net.URLDecoder; import java.net.URLEn ...
- 字节跳动基于Apache Hudi构建EB级数据湖实践
来自字节跳动的管梓越同学一篇关于Apache Hudi在字节跳动推荐系统中EB级数据量实践的分享. 接下来将分为场景需求.设计选型.功能支持.性能调优.未来展望五部分介绍Hudi在字节跳动推荐系统中的 ...
- SQL语句之高级使用
1.select top select top 用于规定要返回的数据的数目 注意:并非所有的数据库系统都支持 SELECT TOP 语句. MySQL 支持 LIMIT 语句来选取指定的条数数据, ...
- LCT 小记
全程 Link-Cut Tree,是解决动态树问题的有力科技 --题记 简单实现 LCT 的形态直观上是一堆 Splay 的合体,每个 Splay 以时间戳为关键字,各个 Splay 通过虚边相连,可 ...