C# 事件
C# 事件
1.事件概述
事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。
C# 中使用事件机制实现线程间的通信。
事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。
发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
2.使用事件有6个步骤:
事件处理程序:由订阅器注册到事件的方法,在发布器触发事件时执行。事件处理程序方法可以定义在事件所在的类或结构中,也可以定义在不同的类或结构中。
(1)声明委托:事件和事件处理程序必须有共同的签名和返回类型,它们通过委托类型进行描述。
(2)声明事件:发布器类必须声明一个订阅器类可以注册的事件成员。当声明的事件为public时,称为发布了事件。
(3)触发事件:发布器类中“触发”事件并导致调用注册的所有事件处理程序的代码。
(4)声明事件处理程序:事件处理程序必须具有与事件的委托相同的返回类型和签名。
(5)订阅事件并添加或删除事件处理程序:订阅者必须订阅事件才能在它被触发时得到通知。
(6)执行触发事件语句。
注意点:声明委托、声明事件、触发事件一般放在发布器类中;
声明事件处理程序一般放在订阅器类中;
订阅事件并添加或删除事件处理程序可以放在主函数中也可以放在订阅器类中
执行触发事件语句一般放在主函数中
3.声明事件:
1.声明事件代码
class Incrementer
{
//event 关键字
//EventHandler 是委托类型(委托类型是什么,这里就是什么),.Net框架提供事件使用的标准模式就是System命名空间声明的EventHandler委托类型(后面会提到)
//CountedADozen 事件名
public event EventHandler CountedADozen;
}
可以使用逗号分隔,同时声明多个事件
public event EventHandler myEvent1,myEvent2,myEvent3;
2.注意事项
(1)事件声明首先需要声明委托(如果使用默认的EventHandler委托类型,就不需要声明委托了),因为声明事件需要使用到委托类型,任何附加到事件的处理程序都必须与委托类型的签名和返回类型匹配。
(2)事件必须声明在一个类中,事件是类或结构的成员,事件成员被隐式自动化为null
(3)声明为public,这样其他类和结构可以在它上面注册事件处理程序。
(4)不能使用对象创建表达式(new 表达式)来创建它的对象。
4.订阅事件:
订阅者向事件添加事件处理程序,事件处理程序必须具有与事件的委托相同的返回类型和签名。
使用+=运算符来为事件增加事件处理程序。
事件处理程序的规范可以是以下任意一种:
实例方法的名称;静态方法的名称;委托形式;匿名方法;Lambda表达式
例如:
//incrementer这个对象是发布器类的对象
//CountedADozen 是事件名
//IncrementDozensCount 是实例方法
incrementer.CountedADozen+=IncrementDozensCount;//使用方法引用形式的实例方法
incrementer.CountedADozen+=ClassB.CounterHandlerB;//使用方法引用形式的静态方法
incrementer.CountedADozen+=new EventHandler (cc.CounterHandlerC);//委托形式
incrementer.CountedADozen+=()=>DozensCount++;//Lambda表达式
incrementer.CountedADozen+=delegate{DozensCount++;}//匿名方法
5.触发事件:
在触发事件之前和null进行比较,从而查看是否包含事件处理程序,如果事件是null,则表示没有,不能执行。
触发事件语法和调用方法一样:使用事件名称,后面跟的参数列表包含在圆括号中;参数列表必须与事件的委托类型相匹配
if(CountedADozen !=null)//确认有方法可以执行
{
//CountedADozen 事件名
CountedADozen (source,args);//触发事件
}
事件声明和触发事件的代码放在发布器类中:
6.完整代码示例:
完整代码展示如下:发布器类Incrementer和订阅器类Dozens,在构造函数中,Dozens类订阅事件,将Incrementer_CountedADozen作为事件处理程序;在Incrementer类的DoCount方法中,每增长5个数就触发CountedADozen事件。
发布器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{//1.声明委托delegate void Handler();//发布器类internal class Incrementer{public event Handler CountedADozen;//2.声明事件public void DoCount(){for (int i = 0; i < 100; i++){if (i%5==0&&CountedADozen!=null) //判断条件{CountedADozen();//3.触发事件}} }}
}
订阅器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{internal class Dozens{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer ){DozensCount = 0;//5.订阅事件并添加事件处理程序incrementer.CountedADozen += Incrementer_CountedADozen;}private void Incrementer_CountedADozen()//4.声明事件处理程序{DozensCount++;}}
}
主函数类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo8_0727
{internal class Program{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozens = new Dozens(incrementer);//6.执行触发事件语句incrementer.DoCount();Console.WriteLine("Number of dozens={0}",dozens.DozensCount);Console.ReadKey();}}
}
7.标准事件用法
.Net框架提供了事件使用的标准模式,.NET 类库中的所有事件均基于 EventHandler 委托,定义如下:
public delegate void EventHandler(object sender, EventArgs e);
//第一个参数用来保存触发事件的对象的引用
//第二个参数用来保存状态信息,指明什么类型适用于该应用程序:
无需声明该委托,因为它已在创建 C# 项目时包括的 System 命名空间中声明。
发布器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Incrementer{//声明事件public event EventHandler CountedADozen;public void DoCount(){for (int i = 0; i < 100; i++){if (i%5==0&&CountedADozen!=null){//触发事件CountedADozen(this,null);}}}}
}
订阅器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Dozens{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer){DozensCount = 0;//订阅事件并添加事件处理程序incrementer.CountedADozen += Incrementer_CountedADozen;}//声明事件处理程序private void Incrementer_CountedADozen(object sender, EventArgs e){DozensCount++;}}
}
主函数类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo9_0727
{internal class Program{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozens = new Dozens(incrementer);//执行触发事件语句incrementer.DoCount();Console.WriteLine("Number of dozens={0}",dozens.DozensCount);Console.ReadKey();}}
}
8.通过扩展EventArgs来传递数据
如果希望传递数据,必须声明一个派生自EventArgs 的类,使用合适的数据来保存需要的数据。
为了向自己的事件处理程序的第二个参数传入数据,需要声明一个派生自EventArgs的自定义类,它可以保存我们需要传入的数据。类的名称应该以EventArgs结尾。
要获得该类,需要使用泛型委托。(后续会提到)
代码演示:
自定义派生类IncrementerEventArgs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{//自定义派生类继承EventArgs类internal class IncrementerEventArgs: EventArgs{public int IterationCount { get; set; }//存储一个整数}
}
发布器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Incrementer1{// 声明事件public event EventHandler<IncrementerEventArgs> CountedADozen;public void DoCount(){ IncrementerEventArgs args=new IncrementerEventArgs();for (int i = 0; i < 100; i++){if (i % 5 == 0 && CountedADozen != null){args.IterationCount = i;CountedADozen(this, args);//在触发事件时传递参数}}}}
}
订阅器类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Dozens1{//int _DozensCount;public int DozensCount{get;private set;}public Dozens1(Incrementer1 incrementer1){DozensCount = 0;incrementer1.CountedADozen += Incrementer1_CountedADozen;}private void Incrementer1_CountedADozen(object sender, IncrementerEventArgs e){Console.WriteLine("Incremented at iteration:{0} in {1}",e.IterationCount,sender.ToString());DozensCount++;}}
}
主类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace demo5_0726
{internal class Program{static void Main(string[] args){Incrementer1 incrementer1 = new Incrementer1();Dozens1 dozens1 = new Dozens1(incrementer1);incrementer1.DoCount();Console.WriteLine("Number of dozens={0}",dozens1.DozensCount);Console.ReadKey(); }}
}

相关文章:
C# 事件
C# 事件 1.事件概述 事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。 C# 中使用事件机制实现线程…...
网络:TCP/IP协议
1. OSI七层参考模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 2. TCP/IP模型 应用层 传输层 网络层 数据链路层 物理层 3. 各链路层对应的名称 应用层对应的是协议数据单元 传输层对应的是数据段 网络层对应的是数据包 链路层对应的是数据帧 物理层对应的是比特…...
在线阅读版:《2023中国软件供应链安全分析报告》全文
聚焦源代码安全,网罗国内外最新资讯! 专栏供应链安全 数字化时代,软件无处不在。软件如同社会中的“虚拟人”,已经成为支撑社会正常运转的最基本元素之一,软件的安全性问题也正在成为当今社会的根本性、基础性问题。 随…...
NLP_文本去重_附Python实现【MinHash和MinHashLSH】算法
NLP_文本去重_附Python实现【MinHash和MinHashLSH】算法 前言代码的实现【注释丰富】前言 大规模的文本去重是目前比较热门的一个技术,由于大模型的兴起,更多的高质量数据集也是大家迫切需要的。 关于如何进行文本去重? 直观的方法首先是利用Python正则表达式进行去重。 推…...
Excel Power View教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 Excel Power View 是一种数据可视化技术,用于创建交互式图表、图形、地图和其他视觉效果,以便直观呈现数据。 Excel Power View中,可以快速创建各种可视化效果,从表格和矩阵到饼图、条形图和气泡图,以及多个…...
关于聊天功能,使用input发送消息,不能在input中显示图片解决办法
一般情况下,发送消息,上传文件、图片都是使用 input 来实现,但是产品的功能千变万化,现实中也会有不尽人意的时候 下方使用了element中的input 绑定Enter事件发送消息,但是有个功能点是 <el-input type"texta…...
SQL语句(三十二)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、SQL语句类型 二、数据库操作 三、数据表操作 1. 数据类型 2. 查看 3. 创建 4. 删除 5. 更改 5.1 表 5.2 列 四、数据操作 4.1 增 4.2 删 4.3 改 4.4 查…...
ffmpeg-aresample_swr_opts的解析
ffmpeg option的解析 ffmpeg -y -i /home/hui/2ch-16k.wav -filter_size 16 -phase_shift 6 -ar 48000 out.wav其中-filter_size 16,-phase_shift 6是被当做option解析的,会进入opt_default函数,因为这两个参数是swresample的,所…...
PX4从放弃到精通(二十九):传感器冗余机制
文章目录 前言一、parametersUpdate二、imuPoll三、 put四、 confidence五、 get_best 前言 PX4 1.13.2 一个人可以走的更快,一群人才能走的更远,可加文章底部微信名片 代码的位置如下 PX4冗余机制主要通过传感读数错误计数和传感器的优先级进行选优 …...
vue 设置数组
手写获取数据 <el-form-item label"缴纳方"><el-select v-model"form.invoiceCategoryName" placeholder"请选择缴纳方"><el-optionv-for"item in kplmList":key"item.value":label"item.label":v…...
9.NIO非阻塞式网络通信入门
highlight: arduino-light Selector 示意图和特点说明 一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 I/O 一连接一线程模型。架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 服务端流程 1、当客户端连接服务端时&…...
QT基于TCP协议实现数据传输以及波形绘制
这个玩意我做了两个,一个是安卓app,一个是Windows程序。代码并非全部都是由我从无到有实现,只是实现了我想要的功能。多亏了巨人的肩膀,开源万岁!!! 我把程序放到GitHub上,需要的可…...
苹果safari浏览器播放不了video标签视频
今天遇到了个神奇的问题,视频文件在pc端和安卓手机上播放都没问题,但是在ios上就是播放不了,大概代码如下: 前端代码: <video id"video" width"350" height"500" controls><s…...
【粒子群算法和蝴蝶算法组合】粒子群混沌混合蝴蝶优化算法研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Java设计模式之单例模式详解(懒汉式和饿汉式)
在开发工作中,有些类只需要存在一个实例,这时就可以使用单例模式。Java中的单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供全局访问点。下面来介绍一下两种常见的单例模式:懒汉式和饿汉式。 一、懒汉式…...
软件测试基本知识
安全测试 安全防护策略?(漏洞扫描、入侵检查、安全日志、隔离防护) 安全日志:用于记录非法用户的登录名称、操作时间及内容等信息,以便发现问题并提出解决措施;安全日志仅记录相关信息,不对非…...
Vue项目中强制刷新页面的方法
我们在动态切换组件的过程中,导航栏和底栏不动,动态切换中间区域的情况,在首页可以进行跳转任意组件,在组件与组件之间不能相互跳转,路由发生了变化,但是页面未改变,这时我们就需要强制刷新页面…...
文件按关键字分组-切割-染色-写入excel
1. 背景 针对下面的文件data.csv,首先根据fid进行排序,然后分组,使相同fid的记录放到同一个excel文件中,并对每列重复的数据元素染上红色。 fid,user_id -1000078398032092029,230410010036537520 -1000078398032092029,23042301…...
爬虫的基本原理:爬虫概述及爬取过程
前言 随着互联网的不断发展和普及,我们的生活越来越离不开网络。而网络世界中有着海量的信息和数据,这些信息和数据对于我们的工作和生活都有很大的帮助。但是,如何高效地获取这些数据呢?这时候,爬虫这个工具就派上用…...
cocos2D插件转3D插件
cocos2D插件转3D插件 use strict;/*** 3d插件api映射,兼容2d插件* */let fs require("fs");let path require("path");let baseDir ;const prsPath (Editor.Project && Editor.Project.path ? Editor.Project.path : Editor.remote.projectP…...
从XJTUSE编译原理小测出发:手把手教你用Python实现一个简易的词法分析器
从理论到实践:用Python构建词法分析器的完整指南 编译原理常被视为计算机科学中的"玄学"——课堂上听得云里雾里,考试时全靠死记硬背。但当我第一次用Python实现了一个能识别简单算术表达式的词法分析器后,那些抽象的状态转换图、有…...
Java毕业设计基于springboot+vue的旧时光咖啡厅管理系统
前言 该系统旨在提高咖啡厅的运营效率和服务质量,通过集成订单管理、库存管理、员工管理、客户管理等多个功能模块,实现对咖啡厅日常运营的全面管理。同时,系统还提供了丰富的数据分析和报表功能,帮助管理者更好地了解咖啡厅的运营…...
视频抠像技术全解析:基于MatAnyone的动态场景处理与多目标分离方案
视频抠像技术全解析:基于MatAnyone的动态场景处理与多目标分离方案 【免费下载链接】MatAnyone MatAnyone: Stable Video Matting with Consistent Memory Propagation 项目地址: https://gitcode.com/gh_mirrors/ma/MatAnyone 视频抠像技术在影视制作、直播…...
2026论文写作工具红黑榜:AI论文平台怎么选?一篇看懂
2026年论文写作工具红黑榜出炉,红榜优先选千笔AI、ThouPen、豆包,适配国内学术规范,提升写作效率与合规性;黑榜需避开低质免费工具、无真实引用平台及过度依赖全文生成的工具。选择时建议按需求匹配度 - 数据可信度 - 成本承受力三…...
Qwen3-32B-Chat模型微调指南:提升OpenClaw任务执行准确率
Qwen3-32B-Chat模型微调指南:提升OpenClaw任务执行准确率 1. 为什么需要微调Qwen3-32B-Chat模型? 在使用OpenClaw进行自动化任务时,我发现某些特定场景下的任务执行准确率始终不理想。比如截图识别文字时,模型经常混淆相似字符&…...
颠覆式开源工具GHelper:极简华硕笔记本硬件控制解决方案
颠覆式开源工具GHelper:极简华硕笔记本硬件控制解决方案 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops. Control tool for ROG Zephyrus G14, G15, G16, M16, Flow X13, Flow X16, TUF, Strix, Scar and other models 项目地…...
数据仓库的设计与实现:从概念到落地
数据仓库的设计与实现:从概念到落地 前言 作为一个在数据深渊里捞了十几年 Bug 的女码农,我深知数据仓库在企业数据管理中的重要性。一个好的数据仓库不仅能帮助企业整合分散的数据,还能为业务决策提供有力支持。今天,我就来聊聊数…...
ACE协议实战:如何通过AxDOMAIN信号优化多核SoC的缓存一致性?
ACE协议实战:AxDOMAIN信号在多核SoC缓存一致性中的深度优化 1. 多核SoC缓存一致性的工程挑战 在现代嵌入式系统设计中,多核处理器架构已成为提升性能的主流方案。当我们把多个ARM Cortex-A系列核心集成到同一芯片时,缓存一致性管理立即成为系…...
vLLM-v0.17.1一文详解:vLLM与MLC-LLM推理框架技术路线对比
vLLM-v0.17.1一文详解:vLLM与MLC-LLM推理框架技术路线对比 1. vLLM框架简介 vLLM是一个专注于大语言模型(LLM)推理和服务的高性能开源库。最初由加州大学伯克利分校的天空计算实验室开发,现已发展成为学术界和工业界共同维护的社区项目。这个框架以其出…...
如何通过铜钟音乐重拾纯粹听歌的乐趣:一个零干扰的Web音乐解决方案
如何通过铜钟音乐重拾纯粹听歌的乐趣:一个零干扰的Web音乐解决方案 【免费下载链接】tonzhon-music 铜钟 (Tonzhon.com): 免费听歌; 没有直播, 社交, 广告, 干扰; 简洁纯粹, 资源丰富, 体验独特!(密码重置功能已回归) 项目地址: https://gitcode.com/G…...
