C#学习笔记 事件

2023-11-20

事件为委托提供了一种发布/订阅机制。声明事件的类被称为发行者类,其他类可以订阅发行者类中的事件。当发行者类触发其中的事件时,所有订阅该事件的类都会收到这个变化。在图形界面框架中,这种情况非常常见。

事件发布者

首先需要创建一个事件发布者类。该类包含一个委托,并有一个基于该委托的事件,还应该有一个可以触发事件的函数,以便订阅者可以在其他地方接收到这个事件。事件常常定义为一个包含事件发布者和事件消息传递的委托。

//事件发布者
class NewsPublisher
{
    //定义事件的委托
    public delegate void NewsEventHandler(NewsPublisher sender, NewsEventArgs args);
    //用委托定义的事件
    public event NewsEventHandler NewsEvent;
    //构造函数,初始化一个发布者的名称
    public NewsPublisher(string name)
    {
        Name = name;
    }
    //发布事件的函数
    public void PublishNews(string News)
    {
        //当事件有订阅者的时候
        if (NewsEvent != null)
        {
            NewsEvent(this, new NewsEventArgs(News));
        }
    }
    public string Name { set; get; }
}

事件传递的消息

跟随事件传递的消息类,既可以是一个包含很多信息的复杂类,也可以是一个仅仅包含一个字符串的简单类。在这里简单的定义一个只包含一条字符串信息的类来传递消息。

//定义需要随事件传递的信息
class NewsEventArgs
{
    public NewsEventArgs(string News)
    {
        this.News = News;
    }
    public string News
    {
        get; set;
    }
}

事件订阅者

有了事件发布者和事件消息之后,就可以定义事件订阅者了。订阅者需要有一个和发布者事件匹配的方法,用来接收事件响应。

//订阅事件的类
class NewsReader
{
    //在构造函数中订阅一个事件
    public NewsReader(string name, NewsPublisher publisher)
    {
        Name = name;
        publisher.NewsEvent += HandleNewsEvent;
    }

    public string Name { get; set; }
    //订阅的方法需要和事件类型匹配
    public void HandleNewsEvent(NewsPublisher sender, NewsEventArgs args)
    {
        Console.WriteLine($"{Name} 收到 {sender.Name} 发来的消息:{args.News}");
    }
}

事件的使用

有了事件发布者和事件订阅者,就可以来看看事件是怎么运作的了。

NewsPublisher publisher = new NewsPublisher("新闻发布者");

NewsReader reader1 = new NewsReader("读者1", publisher);
NewsReader reader2 = new NewsReader("读者2", publisher);
NewsReader reader3 = new NewsReader("读者3", publisher);

Console.WriteLine($"{publisher.Name}发布了一则新闻。");
publisher.PublishNews("早间新闻");

Console.WriteLine($"{publisher.Name}发布了一则新闻。");
publisher.PublishNews("晚间新闻");

这段程序的运行结果如下。从结果可以看出,事件其实就是一个多播委托。同样的,事件订阅者收到事件的顺序和它们订阅的顺序不一定相同,所以不要编写依赖于它们之间顺序的代码。

新闻发布者发布了一则新闻。
读者1 收到 新闻发布者 发来的消息:早间新闻
读者2 收到 新闻发布者 发来的消息:早间新闻
读者3 收到 新闻发布者 发来的消息:早间新闻
新闻发布者发布了一则新闻。
读者1 收到 新闻发布者 发来的消息:晚间新闻
读者2 收到 新闻发布者 发来的消息:晚间新闻
读者3 收到 新闻发布者 发来的消息:晚间新闻

预定义的事件

事件非常地常用,因此微软也为我们预定义了一个泛型委托EventHandler。它的形式如下:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs: EventArgs;

从这个委托的定义可以看出,这里需要的事件消息类需要继承EventArgs。由于这个委托已经定义在System命名空间了,所以不需要再自己手动定义委托了。上面的例子也可以改写一下了。

首先,事件消息类需要继承EventArgs,除此之外不需要做其他的变动。

class NewsEventArgs : EventArgs
{
    public NewsEventArgs(string News)
    {
        this.News = News;
    }
    public string News
    {
        get; set;
    }
}

然后,事件发布者类需要删掉自定义的委托,并把事件类型改为泛型委托EventHandler。

class NewsPublisher
{
    //使用泛型委托EventHandler
    public event EventHandler<NewsEventArgs> NewsEvent;
    //构造函数,初始化一个发布者的名称
    public NewsPublisher(string name)
    {
        Name = name;
    }
    //发布事件的函数
    public void PublishNews(string News)
    {
        //当事件有订阅者的时候
        if (NewsEvent != null)
        {
            NewsEvent(this, new NewsEventArgs(News));
        }
    }
    public string Name { set; get; }
}

事件订阅者里面也要做一些改动,让方法匹配EventHandler的定义。

class NewsReader
{
    //在构造函数中订阅一个事件
    public NewsReader(string name, NewsPublisher publisher)
    {
        Name = name;
        publisher.NewsEvent += HandleNewsEvent;
    }

    public string Name { get; set; }
    //订阅的方法需要和事件类型匹配
    public void HandleNewsEvent(object sender, NewsEventArgs args)
    {
        Console.WriteLine($"{Name} 收到 {((NewsPublisher)sender).Name} 发来的消息:{args.News}");
    }
}

这样,就可以和原来一样的使用事件了。EventHandler非常常用,在Windows图形界面编程里,会经常看到这样的方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#学习笔记 事件 的相关文章

  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • 在.rdlc报告的底部设置一个文本框

    我在 rdlc 报告中使用 tablix 有一个文本框 其中包含文本 签名 我想将此文本框放置在报告最后一页的底部 就在页脚之前 我已经用谷歌搜索了这个解决方案 但没有找到满意的结果 我的环境是VS2010 framework 4 0 有什
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • 使用 System.Text.Json 即时格式化 JSON 流

    我有一个未缩进的 Json 字符串 例如 hash 123 id 456 我想缩进字符串并将其序列化为 JSON 文件 天真地 我可以使用缩进字符串Newtonsoft如下 using Newtonsoft Json Linq JToken
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • 如何衡量两个字符串之间的相似度? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 给定两个字符串text1 and text2 public SOMEUSABLERETURNTYPE Compare string t
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 将 xml 反序列化为类,list<> 出现问题

    我有以下 XML
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框

随机推荐

  • nginx的sticky模块

    Sticky工作原理 Sticky是nginx的一个模块 它是基于cookie的一种nginx的负载均衡解决方案 通过分发和识别cookie 来使同一个客户端的请求落在同一台服务器上 默认标识名为route 1 客户端首次发起访问请求 ng
  • neo4j windows图像界面 如何查询最短路径

    MATCH p1 concept name factor p2 concept name cf4 p allshortestpaths p1 10 p2 RETURN p 注意上述p1是变量这个是通用的 只需要更改concept这个即可 你
  • 使用Notepad++工具查看文件的十六进制

    最近在用notepad 打开 dat文件 想看看里面的一些数据但是打开之后发现是乱码 下面给出解决方法 1 首先打开 dat文件 发现是一些乱码 2 点击 插件 gt 搜索hex gt 找到HEX Editor勾选 gt 安装 3 重新打开
  • stm32对flash的读写保护与解除

    一 STM32对内部Flash的保护措施 所有STM32的芯片都提供对Flash的保护 防止对Flash的非法访问 写保护和读保护 1 读保护即大家通常说的 加密 是作用于整个Flash存储区域 一旦设置了Flash的读保护 内置的Flas
  • Nginx跨域配置

    一 跨域概述 1 1 同源策略 同源策略是一个安全策略 同源 指的是协议 域名 端口相同 浏览器处于安全方面的考虑 只允许本域名下的接口交互 不同源的客户端脚本 在没有明确授权的情况下 不能读写对方的资源 同源策略主要是基于如下可能的安全隐
  • 解决labelImg闪退问题

    问题 打开labelImg按下键盘任意键闪退 解决办法 降低python版本 博主将python版本从3 10降低至3 8 并且重新安装了pyqt5 sip和lxml两个包即可正常使用labelImg
  • 03LinuxC线程学习之线程共享和非共享

    1 线程共享和非共享 1 1 线程共享资源 1 文件描述符表 由于线程间共享进程间的内容 而文件描述符表在主线程的PCB当中 各个线程可以直接去请求访问 所以线程间通信就不需要像进程那样通过管道这些方式通信 2 每种信号的处理方式 即当某个
  • js解决浏览器,SpeechSynthesis不能正常合成中文语音

    工作中遇到 浏览器不能合成语音 解决思路 合成失败时 循环合成列表 找到能正常合成的为止 对于一直不能合成的浏览器 设置开关 关闭循环功能
  • 服务器系统安装蓝牙驱动,安装蓝牙设备 - Windows drivers

    安装蓝牙设备 05 29 2020 本文内容 重要 本主题面向程序员 如果你是遇到蓝牙设备安装问题的客户 请参阅 在 Windows 中配对蓝牙设备 蓝牙配置文件驱动程序有两种安装类型 远程设备的 客户端安装 远程设备在该远程设备上公布其服
  • vc6.0 c语言加油站,第2章 C语言初探:4、在VC6.0下运行C语言程序

    不管你是否决定使用C Free 都建议阅读 在C Free下运行C语言程序 文中讲到了几个重要概念 对初学者大有裨益 Visual C 6 0简称VC或者 VC6 0 确实有点老了 在XP Win7下都可能会存在兼容性问题 在Win8下根本
  • 图解GitHub和SourceTree入门教程

    http blog csdn net collonn article details 39259227
  • 想去游戏公司做游戏,最重要的是什么素养?

    首先 要学会沟通 话说 动过去游戏公司的念头 做游戏 感觉很酷 但是 想想自己一不会编程 二不会画画 做策划 那好像是两边受气里外不是人出事第一个背锅的角色 想想也就想想 不过正好前些天我们发过一篇讲去日本学游戏的文章 说不定能派上用场 前
  • 华为OD机试真题- 学校的位置【2023Q1】【JAVA、Python、C++】

    题目描述 为了解决新学期学生暴涨的问题 小乐村要建所新学校 考虑到学生上学安全问题 需要所有学生家到学校距离最短 假设学校和所有的学生家 走在一条直线上 请问 学校要建在什么位置 能使得学校到各个学生家的距离之和最短 输入描述 输入的第一行
  • sql语句中的空值(null)

    含null值的表达式都为null null null 在判断某个数是否为null的时候不是用等号来表示 而是用 is null 在过滤的时候 可以使用in null 但是使用not in null的时候会报错 因为in函数 是指满足里面的情
  • java入门的第一个程序代码 hello world

    很多人说 学Java真的很难 其实 这是真的 但是高薪之所以为高薪 就是因为它比普通的活难的多 今天是我第一篇的博客 我还是想鼓励想学java技术的小伙伴一起来学 很多事只有去做了 你才能知道自己能不能成功 好了 接下来看Java入门的第一
  • 网易云音乐财报解读:收入大增亏损收窄,“云村”草长莺飞

    独家版权时代结束后 在线音乐产业进入了新的发展阶段 各家音乐平台经营状况备受关注 2月23日 网易云音乐公布了2022年全年财务业绩 财报显示 网易云音乐2022年全年收入为90亿元 较2021年同比增长28 5 值得一提的是 得益于盈利能
  • 数组的一些简单操作,列表改数组,数组合并,数组存取

    数组的简单操作 总用的一些操作 记录一下 要不总忘 1列表改数组 import numpy as np a 1 2 3 4 a np array a 输出a array 1 2 3 4 2数组合并 延竖轴拼接数组 aa np vstack
  • hive中取最大值最小值的函数

    max 和min 函数 select a max b from t group by a select a min b from t group by a max和min函数是取某一列中的最大或者最小值 greatest 和least 函数
  • R数据科学-第九章使用lubridate处理日期和时间

    本章将会使用以下三个包 gt library tidyverse gt library lubridate gt library nycflights13 一 创建日期或时间 表示日期或时间的数据有三种 日期 在tibble中显示为date
  • C#学习笔记 事件

    事件为委托提供了一种发布 订阅机制 声明事件的类被称为发行者类 其他类可以订阅发行者类中的事件 当发行者类触发其中的事件时 所有订阅该事件的类都会收到这个变化 在图形界面框架中 这种情况非常常见 事件发布者 首先需要创建一个事件发布者类 该