路由事件

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

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

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. sql查询第10条到第20条数据

    select top(10) * from T1 where Id >= (select MAX(Id) from (select top(20) * from T1 order by Id) ...

  2. C#多线程---Task实现异步

    一.场景 使用Task来进行累加操作. 二.例子-Task使用 1 using System; 2 using System.Collections.Generic; 3 using System.L ...

  3. 十:JavaWeb中的监听器(一)

    2.1.基本概念 JavaWeb中的监听器是Servlet规范中定义的一种特殊类,它用于监听web应用程序中的ServletContext, HttpSession和 ServletRequest等域 ...

  4. mzy,struts学习(一)

    大家都在讲struts已经过时了,现在都是前后台分离,没有必要去学一个淘汰的框架,但是怎么讲呢?我觉得,struts能够流行那么多年,肯定有它的原因,肯定有很多优秀和好的地方,有一个指导过我的人给我讲 ...

  5. SpringBoot博客开发之异常处理

    异常处理: 背景: 最近在搭建属于自己的个人博客(码农小白的执念),自己搭建后端的时候首先考虑的是异常处理.个人也是一边学习一边做,难免有疏漏的地方,希望朋友们在不对的地方提醒下. 技术栈: spri ...

  6. docker-compose权限不够

    root@kali:~# docker-compose version -bash: /usr/local/bin/docker-compose: 权限不够 chmod +x /usr/local/b ...

  7. 基于Linux的系统排错

    1.系统引导过程概述 2.系统异常及恢复 [1]grub系统引导 1)mbr上446字节丢失 模拟问题: dd if=/dev/zero? of=/dev/vda? bs=446? count=1? ...

  8. Linux复习笔记-001-进程的管理

    1.什么是进程? 进程是已经启动的可执行的程序运行实例. 程序是二进制文件,静态 ./bin/date/ /usr/sbin/ 进程:是程序运行的过程 2.Linux为1的进程? centos5或6为 ...

  9. Redis详解(二)——

    https://www.cnblogs.com/yeya/p/14274948.html https://www.cnblogs.com/liang24/tag/redis/

  10. SVN无法查看最近日志和提交记录

    现象: 使用SVN查看最近的提交记录日志时,最近总是无法显示出全部的日志内容,只能显示到几天之前的日志.就算是自己刚提交的代码也是无法没有记录的. 解决方式:右键选择TortoiseSVN中的&quo ...