C#事件详解及应用示例

简介

        事件是使类具备向其它类通知发生的相关事情的能力。事件被分成两部分:一、引发或发送事件的类(称发布者);二、处理或接收事件的类(称订阅者)。事件也是类型的成员。在 .NET 的桌面应用程序中,按钮、列表框、文本输入框等控件都具有相关的事件,如按键响应、鼠标移动、点击等。

1、事件模型

        事件一定是发布者(类)的内部逻辑触发的。事件的模型由事件发布者事件成员、事件的响应、事件的处理(回调一个方法)及事件的订阅 个部分组成。事件的订阅是以委托类型为基础的约束事件处理与事件绑定关联一起。下面通过一个图了解事件组成及关系。

示例:以 C# 中常见的定时器 Timer 为例,了解事件。

using System;
using System.IO;
using System.Timers;

namespace Fountain.Consoles.App
{
  internal class Program
  {
    static void Main(string[] args)
    {
      try
      {
        // 事件的发布者
        Timer timer = new Timer();
        // 触发事件的逻辑
        timer.Interval = 2000;
        // 事件的订阅者
        Log log= new Log();
        log.RetentionTime = 20;
        // 事件的订阅 (事件处理与事件关联在一起)
        timer.Elapsed += log.Delete;
        // 事件的发布者触发计时开始
        timer.Start();
        Console.ReadLine();
      }
      catch (Exception exception)
      {
        Console.WriteLine(exception.Message);
      } 
    }
  }
  /// <summary>
  /// 日志类
  /// </summary>
  public class Log
  {
    private object locker = new object();

    private int retentionTime = 10;
    /// <summary>
    /// 保留时间
    /// </summary>
    public int RetentionTime 
    {
      get { return retentionTime; }
      set { retentionTime = value; }
    }
    /// <summary>
    /// 事件处理(删除日志文件)
    /// </summary>
    public void Delete(object sender, ElapsedEventArgs e)
    {
      // 日志目录
      string logDirectory = string.Format("{0}{1}",               AppDomain.CurrentDomain.BaseDirectory, "Log");
      try
      {
        lock (this.locker)
        {
          if(Directory.Exists(logDirectory))
          {
            // 获取所有匹配的日志文件
            string[] files = Directory.GetFiles(logDirectory, "*.log");
            // 遍历删除
            foreach (string file in files)
            {
              if (File.GetCreationTime(file).AddDays(this.RetentionTime) < DateTime.Now)
              {
                  File.Delete(file);
                  Console.WriteLine($"日志文件【{0}】被删除。", file);
              }
            }
          }
        }
      }
      catch (Exception exception)
      {
          Console.WriteLine($"删除日志文件异常: {0}", exception.Message);
      }
    }
  }
}
2、事件声明

        .NET 提供了很多带事件的类,如Timer、TextBox、Button 等,对于.NET 提供的,我们只用订阅相关事件,添加事件响应处理方法即可。

        如需自定义一个事件,首先必须在需添加的类中声明该事件的委托类型,然后使用 event 关键字声明事件。

         事件的声明有完整声明简略声明两种方式。下面是事件声明的简单示例:

//声明一个委托类型,专门用来声明事件,约束事件处理器
public delegate void 委托类型名称(处理事件参数);
// 基于委托定义事件
public event 委托类型名称 事件名称;

// 声明委托类型字段
public delegate void TextChangedEventHandler(object sender,KeyEventArgs e);
// 简略声明事件
public static event TextChangedEventHandler TextChangedEvent;

//完整声明
public event TextChangedEventHandler TextChangedEvent
{
  add
  {
    //事件处理器的添加器
    this.TextChangedEventHandler += value;
  }
  remove
  {
    //事件处理器的移除器
    this.TextChangedEventHandler -= value;
  }
}
3、事件属性

1、发布者确定引发事件时间,订阅者确定对事件如何响应。

2、事件可被多个订阅,订阅者可以处理多个发布者的事件。

3、事件未被订阅,则事件不会被引发。

4、事件一般用于用户操作。

5、事件被多个订阅时,引发事件时同步调用事件处理程序。

6、事件基于 EventHandler 与 EventArgs 类。

4、事件与委托

        事件并不是委托,只是借用委托类型来存储或引用事件处理,基于委托约束事件能够发送什么样的消息给事件的订阅者。把事件作为一种特殊的委托的实例,或者说是受限制的委托,是委托一种特殊应用,只是因为:1、事件声明用到了委托类型;2、可以直接用委托调用事件订阅者处理内容。

应用

        本应用示例提供应用程序二个界面数据的同步,扫描界面扫描快递单号后,同步到一个放大展示界面。

事件的参数

using System;
namespace Fountain.WinForm.SyncDisplay
{
  /// <summary>
  /// 事件参数
  /// </summary>
  public class SyncEventArg : EventArgs
  {
    /// <summary>
    /// 快递单号
    /// </summary>
    public string TrackingNo { get; set; }
  }
}

事件发布者类,扫描界面:

using System;
using System.Windows.Forms;

namespace Fountain.WinForm.SyncDisplay
{
  public partial class ScanForm : Form
  {
    //使用默认的事件处理委托,定义消息发布者事件
    public event EventHandler SendMsgEvent;
    /// <summary>
    /// 
    /// </summary>
    public ScanForm()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 界面加载
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ScanForm_Load(object sender, EventArgs e)
    {
      try
      {
        ShowForm showForm = new ShowForm();
        // 事件的订阅 (事件处理与事件关联在一起)
        SendMsgEvent += showForm.SysncTextChaned;
        showForm.Show();
      }
      catch
      {
      }
    }
    /// <summary>
    /// 文本输入框回车事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void TextBoxTrackingNo_KeyDown(object sender, KeyEventArgs e)
    {
      try
      {
        if (e.KeyCode == Keys.Enter)
        {
          if (!string.IsNullOrEmpty(this.TextBoxTrackingNo.Text))
          {
            // 事件触发通知
            SendMsgEvent(this, new SyncEventArg() { TrackingNo = this.TextBoxTrackingNo.Text });
          }
        }
      }
      catch
      {
      }
    }
  }
}

事件订阅者类,显示界面:

using System;
using System.Windows.Forms;

namespace Fountain.WinForm.SyncDisplay
{
  public partial class ShowForm : Form
  {
    /// <summary>
    /// 
    /// </summary>
    public ShowForm()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 响应事件处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    internal void SysncTextChaned(object sender, EventArgs e)
    {
      try
      {
        //取到主窗体的传来的文本
        SyncEventArg arg = e as SyncEventArg;
        this.LabelTrackingNo.Text = arg.TrackingNo;
      }
      catch 
      {
      }
    }
  }
}

效果:

小结

        以上都是事件的相关内容,事件属于C#的高级语法,应用的场景很多。希望通过本篇对大家有帮助,敬请关注后续内容。如需应用示例完整代码关注留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/734383.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

梯度提升决策树(GBDT)的训练过程

以下通过案例&#xff08;根据行为习惯预测年龄&#xff09;帮助我们深入理解梯度提升决策树&#xff08;GBDT&#xff09;的训练过程 假设训练集有4个人&#xff08;A、B、C、D&#xff09;&#xff0c;他们的年龄分别是14、16、24、26。其中A、B分别是高一和高三学生&#x…

[SAP ABAP] 运算符

1.算数运算符 算术运算符描述加法-减法*乘法/除法MOD取余 示例1 输出结果: 输出结果: 2.比较运算符 比较运算符描述示例 等于 A B A EQ B <> 不等于 A <> B A NE B >大于 A > B A GT B <小于 A < B A LT B >大于或等于 A > B A GE B <小…

LLM功能应用的测试艺术:策略与实践

在人工智能技术日新月异的今天,大规模语言模型(LLMs)凭借其强大的自然语言处理能力,正逐渐成为众多应用和服务的核心驱动力。从智能客服到创作辅助,从信息检索到个性化推荐,LLMs的广泛应用对测试策略提出了全新的挑战。本文旨在探讨针对拥有LLM功能的应用或软件,如何制定…

Paxos分布式共识算法

Paxos分布式共识算法 一、简介 Paxos算法是由莱斯利兰伯特(Leslie Lamport)于1990年提出的一种基于消息传递且具有高度容错特性的一致性算法。它主要用于解决分布式系统中如何就某个值达成一致&#xff0c;并保证整个系统的一致性&#xff0c;即使在部分节点发生故障的情况下…

java干货,spring声明式事务

文章目录 一、编程式事务1.1 什么是编程式事务1.2 编程式事务的优缺点 二、声明式事务2.1 什么是声明式事务2.2 声明式事务的优点2.3 Spring 事务管理器2.4 spring 声明式事务使用 一、编程式事务 1.1 什么是编程式事务 编程式事务是指通过手动编写程序来管理事务&#xff0c…

数学建模系列(2/4):建模入门

目录 引言 1. 如何开始数学建模 1.1 选择和描述问题 1.2 提出基本假设 1.3 确定模型类型 2. 建模的数学基础 2.1 线性代数基础 矩阵运算 线性方程组的解法 2.2 微分方程基础 常微分方程 偏微分方程 2.3 统计与概率基础 描述性统计 概率基础 3. 模型的求解方法 …

Python学习打卡:day13

day13 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day1397、初识对象98、类的成员方法类的定义和使用成员变量和成员方法成员方法的定义语法 99、类和对象在程序中通过类来描述基于类创建对象 100、…

Idea安装插件刷Leetcode

一、下载插件 idea版本2022以下两个插件都可以用来刷Leetcode 二、登录Leetcode 获取token 登录 三、配置 配置1 配置2 Code FileName C$!velocityTool.leftPadZeros($!{question.frontendQuestionId},4)$!velocityTool.replace(${question.title}," ","&qu…

awdawdad

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月20日 最后&#xff1a; 十分感谢你可以耐着性子把它读完和我可以坚持写到这里&#xff0c;送几句话&#xff0c;对你&#xff0c;也对我&#xff1a; 1.一个冷知识&#xff1a; …

8路编码器脉冲计数器或16路DI高速计数器,Modbus RTU模块 YL69-485/232

特点&#xff1a; ● 编码器解码转换成标准Modbus RTU协议 ● 可用作编码器计数器或者转速测量 ● 支持8个编码器同时计数&#xff0c;可识别正反转 ● 也可以设置作为16路独立DI高速计数器 ● 编码器计数值支持断电自动保存 ● DI输入和电源之间3000V隔离 ● 通过RS-4…

mysql的安装和连接

一.数据库相关概 念 1.数据库 存储数据的仓库,数据是有组织的进行存储,简称DB。 2.数据库管理系统 操纵和管理数据库的大型软件,简称DBM。 3.SQL 操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。简称SQL。 二.市面上流行的数据库 1.ORACLE 2.MySQL …

2024年6月23日 十二生肖 今日运势

小运播报&#xff1a;2024年6月23日&#xff0c;星期日&#xff0c;农历五月十八 &#xff08;甲辰年庚午月戊午日&#xff09;&#xff0c;法定节假日。今天国际奥林匹克日&#xff0c;坚不可摧的意志&#xff0c;披荆斩棘的豪情&#xff0c;永远值得拥有&#xff01; 红榜生…

使用java +paho mqtt编写模拟发布温度及订阅的过程

启动mqtt 服务 创建项目&#xff0c;在项目中添加模块 添加文件夹 添加maven依赖 <dependencies><dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.0<…

win11家庭版使用自带的Linux子系统并安装docker【全网整合版】

1. 电脑配置项 开发者选项 设置->系统->开发者选项 启用或关闭windows功能 控制面板->卸载程序->启用或关闭windows功能 勾选适用于Linux的Windows子系统和虚拟机平台并重启电脑(首次勾选选项时电脑提示重启) Hyper-V 关键点&#xff1a;win11家庭版在启动…

JAVA同城服务场馆门店预约系统支持H5小程序APP源码

&#x1f4f1;一键预约&#xff0c;畅享无忧体验&#x1f3e2; &#x1f680;一、开启预约新纪元 在繁忙的都市生活中&#xff0c;我们常常因为时间紧张而错过心仪的门店或场馆服务。然而&#xff0c;有了“门店场馆预约小程序”&#xff0c;这些问题都将迎刃而解。这款小程序…

vue3学习教程第四十节(pinia的用法注意事项解构store)

pinia 主要包括以下五部分&#xff0c;经常用到的是 store、state、getters、actions 以下使用说明&#xff0c;注意事项&#xff0c;仅限于 vue3 setup 语法糖中使用&#xff0c;若使用选项式 API 请直接查看官方文档&#xff1a; 一、前言&#xff1a; pinia 是为了探索 vu…

Python3简单实现与Java的Hutool库SM2的加解密互通

1、背景&#xff1a; 因业务需求&#xff0c;需要与某平台接口对接。平台是Java基于Hutool库实现的SM2加密解密&#xff0c;研究了下SM2的加解密算法&#xff0c;网上找的资料&#xff0c;都是说SM2【椭圆曲线】 公钥长【x,y分量 64字节】&#xff0c;私钥短【32字节】&#x…

网络富集显著性检验NEST(?)

https://doi.org/10.1002/hbm.26714 背景 一般情况下&#xff0c;研究者通过评估统计量较大的脑区与功能网络重叠的情况&#xff0c;或者计算网络的体素占比&#xff0c;来确定行为和功能网络的相关性。NEST能检测行为表型和大脑表型的相关性是否富集在特定的功能网络中。例如下…

Golang | Leetcode Golang题解之第166题分数到小数

题目&#xff1a; 题解&#xff1a; func fractionToDecimal(numerator, denominator int) string {if numerator%denominator 0 {return strconv.Itoa(numerator / denominator)}s : []byte{}if numerator < 0 ! (denominator < 0) {s append(s, -)}// 整数部分numer…

食谱API

在当今追求健康与美味完美结合的时代&#xff0c;获取准确而丰富的食品和营养信息变得至关重要。无论是热衷于探索世界各地美食的烹饪爱好者&#xff0c;还是对自身饮食营养严格把控的健康追求者&#xff0c;都离不开可靠的资源。幸运的是&#xff0c;现在有诸如 TheMealDB 和 …