深入浅出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:中断事件路 ...
随机推荐
- WPF 中的 经典的ModelView 通知页面更新 UI
view model ------------------------------------------------------------------------------ using HPCo ...
- Contos 7.x 中Docker安装以及使用
Docker是什么? Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中, 然 ...
- Lambda Expressions and Functional Interfaces: Tips and Best Practices
转载自https://www.baeldung.com/java-8-lambda-expressions-tips 1. Overview Now that Java 8 has reached ...
- linux使用xampp安装MediaWiki环境
1.下载并安装xampp 下载xampp 在下载页面下载. 放置到相应目录 将xampp-linux-x64-5.6.3-0-installer.run文件复制到部署机器的/root目录下 安装 [r ...
- mybatis gengeator一键生成
- Linux centos7 pstree
2021-08-12 1.命令简介pstree (display a tree of processes) 命令用于查看进程树之间的关系,即哪个进程是父进程,哪个是子进程,可以直观地看出是谁创建了谁. ...
- sublime text 3 中文排序插件
ST3 的排序不支持中文按拼音排序,所以需要搞一个插件来支持这一特性 pypinyin 这个库可以把中文转成拼音,可惜不支持 python3.3,而 ST3 内置的 python 就是 3.3 我系统 ...
- 从零开始实现简单 RPC 框架 8:网络通信之 Request-Response 模型
Netty 在服务端与客户端的网络通信中,使用的是异步双向通信(双工)的方式,即客户端和服务端可以相互主动发请求给对方,发消息后不会同步等响应.这样就会有一下问题: 如何识别消息是请求还是响应? 请求 ...
- 【SpringMVC】文件上传与下载、拦截器、异常处理器
文件下载 使用ResponseEntity实现下载文件的功能 index.html <!DOCTYPE html> <html lang="en" xmlns:t ...
- Appium问题解决方案(7)- Could not find 'adb.exe' in PATH. Please set the ANDROID_HOME environment variable with the Android SDK root directory path
背景:运行代码提示找不到ADB An unknown server-side error occurred while processing the command. Original error: ...