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…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...