C#委托五(自定义事件)
事件:
"在发生其他类或对象关注的事情时,类或对象可以通过事件通知他们。发送(或引发)事件的类称为"发行者",接受(或处理)事件的类称为"订户"。"
上面这句话描述了事件的最本质功能,用于底层通知上层。正常的架构设计都是分层结构,而分层结构有一点很重要的就是底层对于上层的无知,当初这样设计是为了解耦,为了更好的面向对象,但是带来的问题是如何解决自下而上的信息流。因为自上而下的调用,我们通过接口就可以搞定一切了,上层可以看到下层提供的服务接口,那么正常的调用可以保证一路向下,底层调用中层提供的服务接口,中层的服务接口的实现中调用了底层的服务接口,这样感觉很是完美的设计模式。每一层都不再依赖彼此,隐藏了实现细节。但是现在遇到一个最简单的问题:如果需要底层来触发上层的行为,如何实现。很多程序员告诉我这个简单,轮询啊,底层不断轮询这一个事情的发生状况,如果发生了则启动一个线程专门去处理这个事情。这种解决方案只需要在底层多开出一个服务接口,该服务接口就是表示目前发生了什么事情,然后上层定时查看该接口,如果发生则采取相应操作。当然该种解决方案也是一种解决途径,但是估计你也觉得不好,第一无法实时,因为轮询,那么必定存在一个时差问题,也就是常说的响应时间问题。还有就是单独的轮询线程需要空间与时间的消耗。最让人郁闷还在于这个对于时空的消耗竟然与响应时间是反相关的,总之你想响应时间短,那么就意味着你不得不浪费大量时空,反之亦然。当然此种方法还要解决多线程冲突的问题,涉及到多线程冲突,锁解锁的问题,那么我觉得就不怕你的逻辑能力有多强,耐心有多大,随着项目规模的变大,线程的变多,你大脑崩溃那是早晚的事情。 此处我们引入事件模式。
先来看看事件的特征: ?发行者确定何时引发事件,订户确定执行何种操作来响应该事件 ?一个事件可以有多个订户。一个订户可处理来自多个发行者的多个事件 ?没有订户的事件永远不会被调用 ?事件通常用于通知用户操作 ?如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序 ?支持异步调用 ?可以利用事件同步线程 ?在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的
C#类库中自带了一大堆事件,尤其那些控件。而对于我说到的这个底层触发上层的问题,那么绝大多数是需要自定义事件的。(库中自带事件的使用我就不讲了,如果这个你不会的话,未免对不起观众了。)所以下面就开始着重讲讲自定义事件的问题:
事件是类和对象向外界发出的消息,事件的执行是通过事件委托的方式,调用我们所准备好的处理方法。要响应某些事件并针对某些事件执行我们指定的方法,需要做到以下几步:
- 声明委托、事件
///定义一个委托 public delegate void TestEventHandler( object sender, TestEventArgs e); ///用event关键字声明事件对象 public event TestEventHandler TestEvent; |
- 添加事件的触发方法,也就是通知接受者方法
//事件触发的方法 protected void OnTestEvent(TestEventArgs e) { if (TestEvent != null ) { TestEvent( this , e); } } |
- 添加事件引发方法
//引发事件的方法 public void RaiseEvent( char keyToRaiseEvent) { TestEventArgs e = new TestEventArgs(keyToRaiseEvent); OnTestEvent(e); } |
- 接受者处本地化响应方法
//定义本地处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型 public void KeyPressed( object sender, TestEventSource.TestEventArgs e) { Console.WriteLine( "发送者:{0},所按得健为:{1}" , sender, e.KeyToRaiseEvent); } |
- 接受者订阅事件
//订阅事件 public void Subscribe(TestEventSource evenSource) { evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed); } //取消订阅事件 public void UnSubscribe(TestEventSource evenSource) { evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed); } |
最终全部代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace ConsoleApplication1
- {
- /// <summary>
- /// 发布事件类
- /// </summary>
- public class TestEventSource
- {
- /// <summary>
- /// 定义事件参数类
- /// </summary>
- public class TestEventArgs : EventArgs
- {
- public readonly char KeyToRaiseEvent;
- public TestEventArgs(char keyToRaiseEvent)
- {
- KeyToRaiseEvent = keyToRaiseEvent;
- }
- }
- ///定义一个委托
- public delegate void TestEventHandler(object sender, TestEventArgs e);
- ///用event关键字声明事件对象
- public event TestEventHandler TestEvent;
- //事件触发的方法
- protected void OnTestEvent(TestEventArgs e)
- {
- if (TestEvent != null)
- {
- TestEvent(this, e);
- }
- }
- //引发事件的方法
- public void RaiseEvent(char keyToRaiseEvent)
- {
- TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
- OnTestEvent(e);
- }
- }
- //监听事件类
- public class TestEventListener
- {
- //定义本地处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型
- public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
- {
- Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);
- }
- //订阅事件
- public void Subscribe(TestEventSource evenSource)
- {
- evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed);
- }
- //取消订阅事件
- public void UnSubscribe(TestEventSource evenSource)
- {
- evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- ///创建事件源对象
- TestEventSource es = new TestEventSource();
- ///创建监听对象
- TestEventListener el = new TestEventListener();
- ///订阅事件
- Console.WriteLine("订阅事件\t");
- el.Subscribe(es);
- ///引发事件
- Console.WriteLine("输入一个字符,再按enter键");
- string str = Console.ReadLine();
- es.RaiseEvent(str.ToCharArray()[0]);
- //取消订阅事件
- Console.WriteLine("\n取消订阅事件\n");
- el.UnSubscribe(es);
- //引发事件
- Console.WriteLine("输入一个字符,再按enter健");
- str = Console.ReadLine();
- es.RaiseEvent(str.ToCharArray()[0]);
- Console.ReadLine();
- }
- }
- }
赋值粘贴即可以执行,且看下面截图执行效果:
C#委托五(自定义事件)的更多相关文章
- C#:委托和自定义事件
1. 委托概述 “委托”相当于C++中的“函数指针”,委托必须与所要“指向”的函数在“参数”和“返回类型”上保持一致; // 定义Person类 public class Person { publi ...
- C# 窗体间传值(使用委托与自定义事件)
using System; using System.Drawing; using System.Windows.Forms; namespace 跨窗体调用控件 { public partial c ...
- 分享一个C#自定义事件的实际应用
在C#.NET的开发中,事件是经常接触到的概念,比如为按钮添加点击事件,并写入点击按钮触发事件要运行的代码.不管是ASP.NET还是WinForm等各种形式的应用程序,最经常是为系统生成的事件写具体代 ...
- javaScript事件机制深入学习(事件冒泡,事件捕获,事件绑定方式,移除事件方式,阻止浏览器默认行为,事件委托,模拟浏览器事件,自定义事件)
前言 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软 ...
- jQuery 学习笔记(5)(事件绑定与解绑、事件冒泡与事件默认行为、事件的自动触发、自定义事件、事件命名空间、事件委托、移入移出事件)
1.事件绑定: .eventName(fn) //编码效率略高,但部分事件jQuery没有实现 .on(eventName, fn) //编码效率略低,所有事件均可以添加 注意点:可以同时添加多个相同 ...
- Qt自定义事件的实现(转)
原文:http://blog.csdn.net/michealtx/article/details/6866094 初学Qt,用了Qt自带的事件,然后想怎么才能定义自己的事件呢?又如何使用自定义事件呢 ...
- JS自定义事件之选项卡
自定义事件是一种处理与DOM产生交互的代码逻辑片段之间耦合的很好的架构方法. 一个简单的jQuery插件——选项卡 让ul列表来响应点击事件.当用户点击一个列表项时,给这个列表项添加一个名为activ ...
- EventHandler委托与自定义委托
http://blog.csdn.net/uuxyz/article/details/7175248 EventHandler委托与自定义委托 自定义委托: //1. public delegate ...
- C# 自定义事件(EventArgs)
1,自定义事件: public class TextChangeEventArgs : EventArgs { private string message; public TextC ...
随机推荐
- 设置cell背景色和选中色
// 设置cell的背景色 UIView *bg = [[[UIView alloc] init] autorelease]; bg.backgroundColor = [UIColor colorW ...
- 结合Wireshark捕获分组深入理解TCP/IP协议栈之TCP协议(TCP报文格式+三次握手实例)
摘要: 本文简单介绍了TCP面向连接理论知识,详细讲述了TCP报文各个字段含义,并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析. 一.概述 TCP是面向连接的可靠 ...
- 微服务API模拟框架frock介绍
本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2016/02/introducing-frock Urban Airship是一家帮助 ...
- 开源分享三(炫酷的Android Loading动画)
开源分享三(炫酷的Android Loading动画) 分享GitHub上的一些Loading,为了提升产品用户体验,一个好的Loading必然是不可缺少的,对于一些耗时需要用户等待的页面来说会转移用 ...
- CentOS 7 下使用yum安装MySQL5.7.20 最简单 图文详解
原文地址:https://blog.csdn.net/z13615480737/article/details/78906598 CentOS7默认数据库是mariadb, 但是 好多用的都是m ...
- mybatis-generator + mysql/ptsql
用了mybatis-generator,我就不再想用注解了,这与我之前说的注解与XML并用是矛盾的,知识嘛,本来就是多元化的,今天喜欢这个,明天喜欢那个,哈哈,看了mybatis-generator下 ...
- Android 动态改变高度以及计算长度的EditText
前段时间项目需求,需要做一个有限制长度的输入框并动态显示剩余文字,同时也要动态改变EditText的高度来增加用户体验.现整理出来与大家分享. 先来看看效果图 看了效果就分享一下布局 <Rela ...
- LeetCode -- 删除链表中值为k的元素
本题目比較直接,一次遍历遇到匹配的元素直接删除(通过n.next = n.next.next)就能够了,仅仅是须要考虑到:1.首节点的情况2.末节点的情况 下面为实现: public ListNode ...
- [React Router v4] Style a Link that is Active with NavLink
We often need to be able to apply style to navigation links based on the current route. In React Rou ...
- 小强的HTML5移动开发之路(29)—— JavaScript回顾4
一.变量的作用域 javascript脚本的执行过程分为两个阶段: 第一阶段,js引擎()先扫描整个javascript代码.当碰到<script>时,会先创建一个全局的活动对象,将< ...