WPF自定义路由事件的实例教程
作者:Charles_Su 发布时间:2022-04-17 13:33:07
路由事件模型
传统的简单事件模型中,在消息激发是将消息通过事件订阅的然后交给事件的相应者,事件的相应者使用事件的处理器来做出相应,这样就存在一个问题,用户控件内部的事件就不能被外界订阅,因为事件的宿主必须能够直接访问到事件的响应者。
路由事件的事件拥有者和事件的相应者之间则没有直接的显式订阅关系,事件的拥有者则只负责激发事件,事件将有谁相应它并不知道,事件的响应者则有事件的 * ,针对事件进行监听,当有此类事件传递至此事件响应者就使用事件处理器来相应事件并决定此事件是否继续传递。比如像上一个程序中的,点击“点我”以后事件就开始激发了,然后事件就会在控件树上进行传递,事件的响应者安装了 * ,当监听到这个事件进行响应,并决定这个事件是否继续传递。
了解了路由事件后,这节来学习一下如何自定义路由事件。
【分析代码】
在演示代码前,我们不妨先看一段Button按钮的Click路由事件源码,从源码中学习一下如何定义路由事件。
在ButtonBase中,跟Click路由事件相关的有如下四处代码:
代码一
代码二
代码三
代码四
第一段是声明了ClickEvent这一路由事件对象,这个不用多说;
第二段是声明了ClickEvent路由事件对象的包装器,它类似于属性的get,set,方便我们从外部把路由事件的处理器附加到路由事件上。当外部进行“+=”操作时,内部就会执行add块,将事件处理附加到Click路由事件上,反之执行“-=”操作时,会执行remove块中的内容;
第三段是构造方法中构建Click路由事件对象,跟创建依赖对象类似的是,路由事件对象的创建也不是直接new,而是通过EventManager类的RegisterRoutedEvent方法进行注册,该方法第一个参数是路由事件的名称,微软约定路由事件名称要跟路由事件对象的包装器名称一致,并且跟路由事件对象去掉Event后缀的字样也要一致。第二个参数是指路由事件的策略,也就是事件传播的形式,有如下三种枚举:
RoutingStrategy.Tunnel:隧道式,是指事件从最外层的控件开始路由,直到路由到控件自己,就像一条自上往下的隧道,从window控件一路通到当前触发事件的控件;
RoutingStrategy.Bubble:冒泡式,这个跟隧道式相反,它是从触发事件的控件向上传播,直到最上层停止;
RoutingStrategy.Direct:直通式,跟原始事件模型一样,不路由,直达事件处理器。
第三个参数是指定该路由事件的事件处理器是什么类型,第四个参数是指定该路由事件对象的宿主类型,第四个参数跟第一个参数共同用于路由事件对象的内部创建使用:构建hash code,确定路由事件对象唯一性,同依赖属性一致,在一个类中不能注册两个同名的路由事件对象。
第四段是激发Click路由事件的方法,事件参数就是在此方法中处理,它是路由事件传播之源。
【自定义路由事件】
下面我们就来根据以上语法,基于ButtonBase创建自己的Click路由事件:
public class MyRoutedEventArgs : RoutedEventArgs
{
public MyRoutedEventArgs(RoutedEvent routedEvent, object source)
: base(routedEvent, source) { }
public string RoutedMessage { get; set; }
}
public class MyButton : ButtonBase
{
public static readonly RoutedEvent MessageEvent =
EventManager.RegisterRoutedEvent("Message", RoutingStrategy.Bubble,
typeof(EventHandler<MyRoutedEventArgs>), typeof(MyButton));
public event RoutedEventHandler Message
{
add { this.AddHandler(MessageEvent, value); }
remove { this.RemoveHandler(MessageEvent, value); }
}
protected override void OnClick()
{
base.OnClick();
MyRoutedEventArgs eventArgs = new MyRoutedEventArgs(MessageEvent, this)
{ RoutedMessage = "自定义路由事件被触发了" };
this.RaiseEvent(eventArgs);
}
}
上述代码中,我创建了一个MyButton,声明了一个MessageEvent路由事件对象,值得注意的是,RegisterRoutedEvent的第三个参数我用的是:
typeof(EventHandler<MyRoutedEventArgs>)
而非:
typeof(RoutedEventHandler)
因为RoutedEventHandler的参数跟我自定义的事件参数不一致,需要使用EventHandler的泛型版指定我的事件参数类型,下面是RoutedEventHandler的声明:
该参数类型是RoutedEventArgs,而我使用的是自定义的MyRoutedEventArgs类型。
XAML部分及事件处理器的代码为:
在外层Grid上设置MyButton的Message事件监听及处理器。
运行效果如下:
点击“你好”,弹出MessageBox提示“自定义路由事件被触发了”。
来源:https://www.cnblogs.com/charlesmvp/p/15230150.html


猜你喜欢
- 我就废话不多说了,大家还是直接看代码吧~import com.alibaba.fastjson.JSON;import java.util.
- 1.例如下面的代码片段,Toast类的第一个参数接受一个Context对象:@Override protected Dialog onCr
- 1、什么是过滤器?在客户端到服务器的过程中,当发送请求时,如果有不符合的信息将会被filter进行拦截,如果符合则会进行放行,在服务器给客户
- JAVA并发编程有界缓存的实现1、有界缓存的基类package cn.xf.cp.ch14;/** * *功能:有界缓存实现基类 *时间:
- 在Android中子线程是不能更新ui的。所以我们要通过其他方式来动态改变ui视图,1、runOnUiThreadactivity提供的一个
- 我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面。要实现访问控制的方法多种多样,可以通
- 介绍主要使用了goole的zxing包,下面给出了示例代码,很方便大家的理解和学习,代码都属于初步框架,功能有了,需要根据实际使用情况完善优
- 在一些场合,我们往往需要使用印章来给每页文档加盖一个印章,以表示该文档经过某个部门的认证的,常规的做法就是打印文档后盖章,如果需要电子档再行
- Android 3.0引入了CursorLoader实现异步加载数据,为了避免同步查询数据库时阻塞UI线程的问题。在API 11之前可以通过
- Java GC 机制与内存分配策略详解收集算法是内存回收的方 * ,垃圾收集器是内存回收的具体实现自动内存管理解决的是:给对象分配内存 以及
- 目前常用的ORM框架有 Mybatis(batis)、MybatisPlus,Hibernate、Jpa等几个框架,今天就简单介绍一下搭建M
- 在使用一些产品列如微信、QQ之类的,如果有新消息来时,手机屏幕即使在锁屏状态下也会亮起并提示声音,这时用户就知道有新消息来临了。但是,一般情
- 在Android开发中很多时候会遇到一屏显示不下所有内容的现象,那大家也知道这个时候肯定会想到用scrollview来进行滚屏显示。这个时候
- 什么是自动装箱,拆箱先抛出定义,Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是
- 前言这篇文章主要是从类中static修饰的成员变量,static修饰的成员方法这两个方面来讲解static,static成员变量的初始化会在
- 有时候有一些DOS命令需要我们在执行程序的时候调用,这需要使用C#提供的相关接口。代码如下,很简单,相信大家都能看懂,我就不赘述了。usin
- 目录1.概览2.自定义枚举方法3.使用 == 比较枚举类型4.在 switch 语句中使用枚举类型5.枚举类型的属性,方法和构造函数6.En
- 1、准备工作首先需要有一个用于旋转的图片需要考虑如何开始、结束、加速、减速2、加速减速原理本次的动画采用RotateAnimation,初始
- 1、继承Threadpublic class T4 {public static void main(String[] args) {Sys
- 不啰嗦,上菜 QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.se