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#学习笔记 事件 的相关文章

  • 在 DataGridView 中隐藏行非常慢

    我在 Winforms 应用程序中有一个 DataGridView 大约有 1000 行 未绑定 和 50 列 隐藏一列需要整整 2 秒 当我想隐藏大约一半的行时 这就成为一个问题 private void ShowRows string
  • 操作/Lambda 表达式内存管理问题

    我将一个操作存储在局部变量中 然后在该局部变量超出范围后使用 使用前是否有被清理的危险 这是一个例子 public List GetMaps Action
  • 有没有办法将 boost::json::serializer 切换为美化输出?

    Using boost json serializer如中的示例所示文档 快速查看 http vinniefalco github io doc json json usage quick look html以紧凑格式保存 json tre
  • 使用 size_t 值反向遍历向量

    我想以相反的方向遍历向量的值 如您所知 向量的大小为 size t 当我使用以下代码时 for size t r m size 1 r gt 0 r x r f r for size t c r 1 c lt m size c x r m
  • 在 C++ 中使用表达式模板进行符号微分

    如何在 C 中使用表达式模板实现符号微分 一般来说 您需要一种表示符号的方法 即编码的表达式模板 例如3 x x 42 以及一个可以计算导数的元函数 希望您对 C 中的元编程足够熟悉 知道这意味着什么和需要什么 但可以给您一个想法 This
  • 读取STM32 MCU SPI数据寄存器的值

    有很多类似的问题 但似乎没有一个问题完全相同 我正在将 STML4 MCU 连接到 6 轴传感器 LSM6DS3 我已经成功地在 I2C 中实现了所有内容 但想要 SPI 的额外速度 和 DMA 如果我能让这些第一步工作起来的话 因此 第一
  • WinForms - 表单大小错误

    我们有以下代码 private void MainForm Shown object sender EventArgs e RepositionForm private void RepositionForm Rectangle rect
  • C++:初始化静态字符串成员

    我在 C 中初始化静态字符串成员时遇到一些问题 我有几个类 每个类都包含几个表示 id 的静态字符串成员 当我通过调用静态函数初始化变量时 一切都很好 但是 当我想为一个变量分配另一个变量的值时 它仍然保留空字符串 这段代码有什么问题 st
  • 命名空间“Microsoft”中不存在类型或命名空间名称“Practices”

    我正在使用 Microsoft Visual Studio 2005 for c 我的代码中有以下命名空间 using Microsoft Practices EnterpriseLibrary using Microsoft Practi
  • C for 循环索引:新 CPU 中的前向索引更快吗?

    在我订阅的邮件列表上 两位知识渊博的 IMO 程序员正在讨论一些优化的代码 并说了以下内容 在 5 8 年前发布的 CPU 上 向后迭代 for 循环稍微快一些 e g for int i x 1 i gt 0 i 因为比较i归零比将其与其
  • 本地主机上的 .net HTTP_X_FORWARDED_FOR NULL

    抱歉 如果其他地方已经回答了这个问题 我找不到它 如果没有 我会尝试查找访问过该站点的机器的原始 IP 根据我的基本理解 变量HTTP X FORWARDED FOR无论代理和其他过滤器如何 都会显示用户的 IP 如果这是真的 我正在尝试对
  • ASP.NET MVC 路由 - 向路由添加 .html 扩展名

    我对 MVC 和路由非常陌生 我被要求修改一个应用程序以使用不同的 url 由于我没有经验 这项任务对我来说有点困难 好吧 让我们谈谈一些代码 routes MapRoute CategoryBySeName Route name prod
  • 带双重检查锁的单例设计模式

    假设您有以下代码 1 为什么我们使用双重检查锁 为什么单锁不够好 请提供详细的例子 2 这种实施方式的主要缺点是什么 我该如何证明呢 Thanks public sealed class SomeSingleton5 private sta
  • 只读有运行时开销吗?

    出于某种原因 我一直认为readonly字段有与其相关的开销 我认为这是 CLR 跟踪是否存在readonly字段是否已初始化 这里的开销是一些额外的内存使用量 用于跟踪状态以及分配值时的检查 也许我这么认为是因为我不知道readonly字
  • SQL参数化查询不显示结果

    我的 DataAcess 类中有以下函数 但它没有显示任何结果 我的代码如下 public List
  • OpenGL 计算着色器调用

    我有一个与新计算着色器相关的问题 我目前正在研究粒子系统 我将所有粒子存储在着色器存储缓冲区中 以便在计算着色器中访问它们 然后我派遣一个一维工作组 define WORK GROUP SIZE 128 shaderManager gt u
  • 如何在 Winform DataGridView 中创建不同的单元格格式

    我有一个 DataGridView 我将其绑定到 DataTable DataTable 是一个全数字值 要求 DataGridView 中的每 n 行都包含文本 而不是数值 以便在视觉上为用户分隔部分 我很高兴在绑定后将此文本数据放入 D
  • 获取会议组织者邮件地址 EWS API

    我想使用 EWS API 获取会议组织者的邮件地址 目前 我刚刚获得约会项目的一些属性 我听说你可以设置你想要获取哪些属性 我的代码看起来像这样 CalendarView cview new CalendarView start end c
  • 从 STL 列表中删除项目

    我想创建一个函数 如果符合特定条件 则将项目从一个 STL 列表移动到另一个列表 这段代码不是这样做的方法 迭代器很可能会被擦除 函数失效并导致问题 for std list
  • 如何在用户空间程序中使用内核 libcrc32c (或相同的函数)?

    我想在我自己的用户空间程序中进行一些 CRC 检查 我发现内核加密库已经在系统中 并且支持 SSE4 2 我尝试直接 include

随机推荐

  • 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#学习笔记 事件

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