C#编程语言之委托与事件(二)—— C#事件
前面已经大致讲述了C#委托的一些基础知识点,本文接下来的内容是C#中的事件(Event),在此我提个建议,如果是刚接触C#的委托类型的朋友可以先看到这里,等熟悉了委托的使用之后(大约1-2天)再来了解C#中事件的使用,以免看了以下内容发生思维紊乱的现象。之所以这么说并没有些许自大之意,而相反的是恰恰是认为自己的文章写得结构混乱,不足以明理,如果同时看了委托(delegate)和事件(event)容易知识点混淆,所以只是稍作提醒。
好了,废话不多说,现在进入正题:
事件是什么?C#事件是一种具有特殊签名的委托,且在声明事件类型的时候用event关键字修饰。
说到事件,大家第一个想到的一般都是按钮点击事件,既然说到按钮点击事件,下面就着按钮事件作为例子说开去。
首先,在Winform界面拖拽一个按钮,双击按钮,代码会自动定位到按钮点击函数,右击点击事件的函数名,查找所有引用,可以看到总共包括以下两处引用:
private void button1_Click(object sender, EventArgs e) {}
this.button1.Click += new System.EventHandler(this.button1_Click);
在上面为什么我要特别提到定位到第一个语句是一个函数,而不是事件,因为真正的时间是那个 button1.Click 而不是那个 button1_Click ,因为经常听到有人提到说“双击按钮定位到按钮点击事件”,个人感觉这个说法对事件的概念有失偏颇,顺带地提一提。
在此可以看到函数的参数列表(object sender, EventArgs e),这个参数列表必须是确定的,一个表示点击事件的执行者,一个表示事件参数类,不局限于object和EventArgs,但必须是这个两个类的子类或本身。
下面看一下创建一个事件的步骤:1
(1)、定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象
(2)、定义事件参数类,此类应当从System.EventArgs类派生
(3)、定义事件处理方法,此方法符合步骤(1)定义的委托签名
(4)、用event关键字定义事件对象,它同时也是一个delegate对象
(5)、用+=操作符添加事件到事件队列当中,-=操作符把事件从事件队列中删除
(6)、在需要触发事件的地方调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。
下面我们通过模拟一个Button点击事件来深入了解:
using System;
namespace ConsoleApplication {
//(1)定义一个delegate对象类型
delegate void myEventHandle(object sender, EventArgs e);
class MyEventArg : EventArgs {
//(2)定义事件类,应派生于EventArgs类
public string EventArgsName() {
return "[MyEventArgsName]";
}
}
class _Button {
//(4)定义事件对象,注意关键字和类型
public event myEventHandle Click;
protected void OnUtilEvent(MyEventArg e) {
if(null != Click) {
Click(this, e);
}
}
public void RaiseEvent() {
MyEventArg e = new MyEventArg();
OnUtilEvent(e);
}
public string ButtonName() {
return "[myButtonName]";
}
}
class EventTest {
//(3)定义事件处理方法,保证函数列表和返回值的有效性
static void _Button_Click(object sender, EventArgs e) {
Console.WriteLine("\nYou have clicked the button");
Console.WriteLine("The eventObject is :\t"+(sender as _Button).ButtonName());
Console.WriteLine("The eventArgs is:\t"+(e as MyEventArg).EventArgsName());
}
static void Main() {
_Button _button = new _Button();
//(5)用操作符把事件添加到事件队列当中
_button.Click += new myEventHandle(_Button_Click);
Console.Write("Do you want to click the button(Y/N)");
if (Console.ReadKey().KeyChar == 'Y')
_button.RaiseEvent();
else
Console.WriteLine("The event does not raise");
}
}
}
其中我已经把创建步骤写成注释表明在代码中了,模拟鼠标点击事件我们修改为按下“Y”触发,当看到 _button.Click += new myEventHandle(_Button_Click); 有没有恍然大悟的感觉。其实原理并不难,多练习几次条理就清晰。书读百遍,其义自现,说的亦是如此。
使用某IDE编写以上例子的时候可能在 if(null != Click){ Click(this,e); } 这段语句时会报一个[NOTICE],提示该表示方法可以简单化,可以改成 Click?.Invoke(this, e); 注意这不是错误,如此表示只是为了降低理解难度,其实两个语句的作用是一样的,判断Click对象是否为null,然后执行该事件。
事件发布器:
通过一个例子来直接了解事件发布
using System;
namespace ConsoleApplication {
public delegate void myEventHandle(object sender,FoodEventArg e);
public class FoodEventArg : EventArgs {
private string food;
public FoodEventArg(string food) {
this.food = food;
}
public string getFood() {
return food;
}
}
class Person {
private string name;
public Person(string name) {
this.name = name;
}
public void FoodRecive(object sender,FoodEventArg e) {
Console.WriteLine("{0} receives {1}",name,e.getFood());
}
}
class Dealer {
public event myEventHandle FoodInfo;
public void Receive(string food) {
Console.WriteLine("Dealer: food->{0}",food);
RaiseEvent(food);
}
protected void RaiseEvent(string food) {
FoodInfo?.Invoke(this, new FoodEventArg(food));
}
}
class EventTest {
static void Main() {
Dealer _dealer = new Dealer();
Person _personA = new Person("Evan");
Person _personB = new Person("Cathy");
_dealer.FoodInfo += _personA.FoodRecive;
_dealer.Receive("Rice");
_dealer.FoodInfo += _personB.FoodRecive;
_dealer.Receive("Potato");
_dealer.FoodInfo -= _personA.FoodRecive;
_dealer.Receive("Cucumber");
}
}
}
使用Dealer的FoodInfo事件,通过“+=”来注册一个订阅(实质上就是把一个事件添加到事件队列当中),通过“-=”来取消一个订阅。
例子中食物(Food)的接收一个事件参数,当一个食物被接收时,查看有多少用户订阅该事件可以接收到该食物,一开始只有Even订阅了事件,所以Even接收到了Rice,然后Cathy注册了订阅,所以Even和Cathy(队列结构)依次接收到了Potato,随后Even取消了订阅,所以后来的Cucumber只有当前注册订阅用户Cathy能够接收。
懒得手写运行结果,以下贴出运行结果图:

通过这个例子能够比较清楚地明白C#事件当中 事件执行 者和 事件参数 的作用,C#事件是一种新的类型处理方式,同时更是一种设计模式。
声明:以上 C#编程语言之委托与事件(一)和 C#编程语言之委托与事件(二)均由本人原创编写,文中的每一处代码均经过本人亲自测试能够按照文中所述的结果呈现,如果问题,请及时告知。
文章引用:
1、http://www.cnblogs.com/xlx0210/archive/2010/08/08/1794959.html
尊重知识产权,争取共同进步!
C#编程语言之委托与事件(二)—— C#事件的更多相关文章
- C#特性知识图谱-二、事件
C#特性知识图谱-二.事件 二.事件 在事件驱动的软件系统中,符合某种预设条件的情形出现是,一个事件就会被触发. 2.1 事件三要素 事件源:激发事件的对象 事件信息:事件本身说携带的信息 事件响应者 ...
- javaScript事件(二)事件处理程序
一.事件 二.事件流 以上内容见:javaScript事件(一)事件流 三.事件处理程序 前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应 ...
- 解密jQuery事件核心 - 委托设计(二)
第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...
- Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制
一.事件的捕获与冒泡 由W3C规定的DOM2标准中,一次事件的完整过程包括三步:捕获→执行目标元素的监听函数→冒泡,在捕获和冒泡阶段,会依次检查途径的每个节点,如果该节点注册了相应的监听函数,则执行监 ...
- .NET Core 跨平台物联网开发:设置委托事件(二)
系列教程目录 (一) 连接阿里云IOT (二) 设置委托事件 (三) 上报属性 (四) SDK文档 属性.方法.委托.类 http://pan.whuanle.cn/index.php?dir=up ...
- C++模拟C#事件委托机制(二)
原文 来自于http://www.cnblogs.com/netssfy/archive/2010/02/02/1662056.html 为了解决非法地址访问的冲突,首先需要知道发生该错误的原因是什么 ...
- HTML 事件(二) 事件的注册与注销
本篇主要介绍HTML元素事件的注册.注销的方式. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流.事件委托 4. ...
- HTML 事件(三) 事件流与事件委托
本篇主要介绍HTML DOM中的事件流和事件委托. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4 ...
- js事件捕获,事件冒泡,事件委托以及DOM事件流
一:DOM事件流: 事件流是从页面接收事件的顺序,DOM2级事件规定事件流包括三个阶段: ①事件捕获阶段:用意在于事件达到目标之前捕获它,在事件捕获阶段事件流模型:document→html→body ...
随机推荐
- Adobe RIA 开发工程师认证考试大纲
AdobeRIA 开发工程师认证考试大纲 考题数量:共90道题,考试通过正确率:60% 考试时间:120分钟 试题种类:单选题.多选题和判断题 1. Adobe RIA基础知识(2道题) ...
- FPGA 状态机设计
数字系统有两大类有限状态机(Finite State Machine,FSM):Moore状态机和Mealy状态机. Moore状态机 其最大特点是输出只由当前状态确定,与输入无关.Moore状态机的 ...
- 【原】storm组件(架构层面)
Strom集群遵循从主模式,主与从之间通过Zookeeper协作.架构层面上包括三个组件: 1) Nimbus Node 2)Supervisor Nodes 3)Zookeeper 其中Nimbus ...
- C# 高效字符串连接 StringBuilder介绍
在介绍StringBuilder之前,必须要先了解string的特性. string在.NET中属于基本数据类型,也是基本数据类型中唯一的引用类型.字符串可以声明为常量,但它却放在了堆中. 一:不可改 ...
- 爬虫工具fiddle在firefox浏览器中的使用
1.fiddle工作原理 浏览器与服务器之间通过建立TCP连接以HTTP协议进行通信,默认通过自己发送HTTP(或HTTPS)请求到服务器. 使用Fiddler之后,浏览器像目标服务器发送的请求都会经 ...
- JavaScript函数与对象
函数 函数的定义 JavaScript中的函数和Python中的非常类似,只是定义方式有点区别. // 普通函数定义 function f1() { console.log("Hello w ...
- 【BZOJ2006】超级钢琴(主席树,优先队列)
[BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...
- 原根求解算法 && NTT算法
原根求解算法: 获取一个数\(N\)的原根\(root\)的算法 #include<bits/stdc++.h> #define ll long long #define IL inlin ...
- [BZOJ2503][HAOI2006]均分数据
BZOJ Luogu sol 如果已经确定了一个序列,现要求把这个序列分成m个连续段作为答案,那么就可以用一个显而易见的DP DP显然可以得到当前序列下的最优解. 所以模拟退火瞎JB改一改序列每次DP ...
- CDQ分治 陌上花开(三维偏序)
CDQ分治或树套树可以切掉 CDQ框架: 先分 计算左边对右边的贡献 再和 所以这个题可以一维排序,二维CDQ,三维树状数组统计 CDQ代码 # include <stdio.h> # i ...