路由事件

为了方便程序中对象之间的通信常常需要我们定义一些路由事件。使用路由事件比直接事件方便得多。

创建自定义路由事件的步骤:

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的更多相关文章

  1. 《深入浅出WPF》笔记——事件篇

    如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...

  2. [转]深入浅出WPF(7)——数据的绿色通道,Binding

    本文转自:http://liutiemeng.blog.51cto.com/120361/95273 小序: 怎么直接从2蹦到7啦?!啊哦,实在是不好意思,最近实在是太忙了,忙的原因也非常简单——自己 ...

  3. WPF的路由事件、冒泡事件、隧道事件(预览事件)

    本文摘要: 1:什么是路由事件: 2:中断事件路由: 3:自定义路由事件: 4:为什么需要自定义路由事件: 5:什么是冒泡事件和预览事件(隧道事件): 1:什么是路由事件 WPF中的事件为路由事件,所 ...

  4. 深入浅出WPF(1)—转(http://liutiemeng.blog.51cto.com/120361/91631/)

    深入浅出WPF(1)——什么是WPF 2008-05-15 19:06:00   小序:   Hi,大家好!几乎两个月没有写技术文章了.这两个月,我在学习WPF.回顾一下两个月的学习历程,有两个感觉— ...

  5. 《深入浅出WPF》 学习笔记

    <深入浅出WPF> 序言 1. 什么是WPF    2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...

  6. 【【分享】深入浅出WPF全系列教程及源码 】

    因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...

  7. WPF 冒泡路由事件

    在WPF中,例如,可以构建一个包含图形的按钮,创建一个具有文本和图片混合内容的标签,或者为了实现滚动或折叠的显示效果在一个特定的容器中放置内容.甚至可以多此重复嵌套,直到达到您所希望的层次深度. 这种 ...

  8. C# event 事件学习

    C# event 事件学习 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-26 章节: 简单事件编写 模拟 WPF 控件传递 ...

  9. saltstack之salt event事件用法

    event是一个本地的ZeroMQ PUB Interface,event是一个开放的系统,用于发送信息通知salt或其他的操作系统.每个event都有一个标签.事件标签允许快速制定过滤事件.除了标签 ...

  10. WPF中的事件及冒泡事件和隧道事件(预览事件)的区别

    WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别   WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别 本文摘要: 1:什么是路由事件: 2:中断事件路 ...

随机推荐

  1. 关于c#:如何在不同的命名空间中处理相同的类名?

    How to handle same class name in different namespaces? 我正在尝试创建一个通用的库结构. 我通过为我想要的每个公共库创建单独的项目来做到这一点 我 ...

  2. react启动报babel-eslint依赖版本不一致

    遇到的问题: gitlab上拉的react的项目,下载依赖之后,yarn start启动报错 因为按他说的步骤:1.改动比较大, 2.完全没什么作用(重点) 解决方案:直接忽略,如果项目没有.env文 ...

  3. ES6两种静态属性的书写方法

    1.这种可以不用实例化对象就能输出. class Car{ constructor(){ } } Car.tool=4 console.log(Car.tool);//4 2.必须实例化后才能输出.但 ...

  4. 两种github action 打包.Net Core 项目docker镜像推送到阿里云镜像仓库

    两种github action 打包.Net Core 项目docker镜像推送到阿里云镜像仓库 1.GitHub Actions 是什么? 大家知道,持续集成由很多操作组成,比如抓取代码.运行测试. ...

  5. 基于Linux系统的MariaDB数据库的安装配置

    数据库是指长期存储在计算机内.有组织的和可共享的数据集合.表是数据库存储数据的基本单位,一个表由若干个字段组成 MariaDB 数据库管理系统是 MySQL 的一个分支,主要由开源社区在维护,采用 G ...

  6. Charles-抓取https请求

    在未经设置之前,Charles是无法抓取https请求的,会出现unknown的标识.我们可以通过以下两步设置,解决该问题. 第一步:安装证书 https是在http的基础上加入ssl层,通过ssl来 ...

  7. noip模拟43

    A. 第一题 儿子遍历顺序按深度由小到大即可 B. 第二题 二分最小值,以点权作为初始距离跑最长路即可 直接用大根堆跑 \(dij\) 会 \(T\),考虑初始权值可以处理,且边权一定,用类似蚯蚓的方 ...

  8. noip模拟41

    A. 你相信引力吗 很明显的单调栈的题,考场上没有想到平移最大值,而是想着复制一倍序列破环成链,然后发现最大值的部分特别难维护,而且耗费时间过长,只好牺牲时间复杂度加了个 \(map\) 去重. 首先 ...

  9. jvm学习笔记:程序计数器

    程序计数器(PC Register) The Java Virtual Machine can support many threads of execution at once (JLS §17). ...

  10. uni-app 登录Abp VNexe并获取Token

    uni.request方式登录abp关键代码如下,因abp获取token需要用formdata方式请求所以需要加上请求头 const baseUrl = 'http://127.0.0.1:44323 ...