.NET学习笔记(六) ------事件

.NET delegate 委托 、 Event 事件,接口回调,发布、订阅 另外,它还有两个 方法,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委 托类型的方法和取消注册。委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数 来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else (Switch)语句,同时使得程序具有更好的可扩展性。在类的外部,注册“+=”和注 销“-=”的访问限定符与你在声明事件时使用的访问符相同。用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。.... 阅读详情

事件其实也是属于类型设计里的内容,不过因为他比较重要,也比较难理解,我就把他单独拿出来学习。

1:下面是一个我们在程序中最常见的代码:

private   void  button1_Click( object  sender, System.EventArgs e)
  {
          //按妞被点击后执行的操作;    
 }

他的意思是当你点击一个按钮时,他就会执行这个方法里的代码,产生相应的操作。这个时候我们就可以说‘单击’button1这个事件发生的时候,他会自动去执行这个方法。这看起来很简单。点一个按钮,然后执行代码。这在这种基于驱动的程序中很常见。但有个问题不知道大家有没有想过。

这段代码写在那?一般是写在一个from类里,我点这个按钮属于button类。我实际实在button对象里调用了form对象里的方法。那为什么在点按钮的时候他会执行这个方法呢?

说简单点,就是其实就是在一个对象在执行一个方法时调用其他对象的方法。按事件来说就是一个对象的某个事件被触发时,通知其他对象,其他对象执行相应的一些操作。这里就是button的click事件触发后,通知form对象,执行button1_click()方法。那么当事件触发后是如何通知其他对象的呢?

//  button1
//  登记方法到button对象
this .button1.Click  +=   new  System.EventHandler( this .button1_Click);

在程序中可以看到button1在设置时有这样一句话,他的基本意思就是把button1_click()方法登记到button1.Click对事件象上,这样当触发click事件时就会调用button1_click()方法。也就达到了通知的目的。其中button1.Click又是一个EventHandler类型,这是一个委托类型!什么是委托类型?

 

2:MSDN中对事件和委托的定义

关于委托可以看另外一篇介绍委托的  .NET学习笔记(八) ------委托(上)

事件是对象发送的消息,以发信号通知操作的发生。操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。引发(触发)事件的对象叫做事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。

在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。.NET Framework 定义了一个特殊的类型( Delegate ),该类型提供函数指针的功能。

委托是一个可以对方法进行引用的类。与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用。这样,委托就等效于一个类型安全函数指针或一个回调。虽然委托具有许多其他的用途,但这里只讨论委托的事件处理功能。

 

3:事件完整的例子

下面是一个完整的例子,一个邮件接受类MailManager,当接受到邮件的时候,就会通知Fax类,Fax就回进行一些操作。2个类型在后面简单的称为A,B。

   //A:
class  MailManager
{
    
//定义MailMsgEventArgs类型
    public class MailMsgEventArgs : EventArgs
    
{
        
//1.传递给事件接受者类型定义信息
        public readonly String from,to,subject,body;
        
        
public MailMsgEventArgs(String from,String to,String subject,String body)
        
{
            
this.from = from;
            
this.to = to;
            
this.subject = subject;
            
this.body = body;
        }

    }


    
//2.下面委托类型定义了接受者必须实现的回调方法原型
    public delegate void MailMsgEventHandler(Object sender,MailMsgEventArgs args);

    
//3.事件成员
    public event MailMsgEventHandler MailMsg;

    
//4.下面的受保护虚方法负责通知事件的登记对象
    protected virtual void OnMailMsg(MailMsgEventArgs e)
    
{
        
//有对象登记事件?
        if(MailMsg != null)
        
{
            
//如果有,则通知委托链表上的所有对象
            MailMsg(this,e);
        }


    }


    
//5.下面的方法将输入转化为期望的事件,该方法在新的电子邮件信息到达时被调用
    public void SimulaterArrivingMsg(String from,String to,String subject,String body)
    
{
        
//构造一个对象保存希望传递给同志接受者的信息
        MailMsgEventArgs e = new MailMsgEventArgs(from,to,subject,body);
        
//调用虚方法同志对象事件已发生
        
//如果派生类型没有重写该虚方法,对象将通知所有登记事件监听者
        OnMailMsg(e);
    }


}

A这个类型是一个事件的发送方,其中定义了事件成员和其他一些方法。他就相当于前面说到的button类,当这个类型中的事件被触发是,他就通过委托来通知登记的对象。

class  Fax
{
    
//1:将MailManager对象传递给构造器
    public Fax(MailManager mm)
    
{
        
//构造一个指向FaxMsg回调方法的MailMsgEventHandler
        
//委托实例,然后登记MailManager的MailMsg事件
        mm.MailMsg +=new MailManager.MailMsgEventHandler(FaxMsg);

    }


    
//2:MailManager将调用该方法来通知Fax对象收到一个新的电子邮件消息
    private void FaxMsg(Object sender,MailManager.MailMsgEventArgs e)
    
{
        
//参数sender表示MailManager对象,如果期望和事件的触发者通信,将会用到该参数
        
//参数e表示MailManager对象希望提供的一些附加事件信息
        Console.WriteLine("Faxing mail message:");
        Console.WriteLine(
"From:{0}  To:{1}  Subject:{2}  Body:{3} ",e.from,e.to,e.subject,e.body);
    }

 
       //3:取消登记
    
public void Unregister(MailManager mm)
    
{
        MailManager.MailMsgEventHandler callback 
= new MailManager.MailMsgEventHandler(FaxMsg);
        mm.MailMsg 
-=callback;
    }

}

B这个类型是一个事件接受者,我们看到在内部构造的时候,他已经把自己的方法登记到前面的事件发送者上了。这样在当A中的事件被触发时,B就会接到通知,因为B把自己的方法委托给了A,所以A还会调用B中的方法。

 

4:下面是具体对事件模型的讨论

事件发送者:
1:在类型中定义一个EventArgs类型:用来保存要发送给事件接受者的附加信息。如果没有要传递的信息,可以直接使用系统的EventArgs.Emepty而不用在构造新的EventArgs对象。

2:定义一个委托类型:指定事件触发时接受者中被调用的方法的原形。如果我们定义的事件没有需要传递给事件接收者的附加信息,我们便不必定义新的委托类型。直接使用FCL中的System.EventHandler,并将EventArgs.Emepty传递给第2个参数。

3:定义一个事件成员:他是EventHandler委托类型。定义他意味着,事件的接受者想要处理这个事件,他们对应必须具有和委托类型相同签名的回调方法。

4:定义一个虚方法:当事件发生时调用这个方法,这个方法负责通知登记的接收者对象。该方法接收一个EventArgs参数。这个方法先检查是否有对象登了事件,也就是委托类型的事件成员是不是为空。如果不为空,就触发事件,然后登记的接收者对象的一个方法会被调用。这个方法必须和第2步中定义的委托类型的方法有完全匹配的签名。
这个方法是一个虚方法,所以他的继承类可以根据需要重写此方法,使得派生类可以控制事件的触发。通常派生类应该先调用基类的此方法,这样可以使所有已经登记事件的对象都能接受到通知。但是派生类也可以决定不让事件继续传递下去。

5:最后还需要定义一个方法,把外部的输入转换为触发事件的动作。当程序调用这个方法时,这个方法内部会构造EventArgs来产生要触发事件时要传递的信息,并调用上面的虚方法来触发事件。从而通知登记的对象,执行接受者中的回调方法。此方法也可以被派生类重写。


事件接受者:
1:事件接受者在事件发生时能接受到通知,然后执行自己的一个方法。这个方法必须和事件发送者中委托类型的签名完全匹配,才能在接受到通知时被调用。

2:事件接受者想要能接受事件发送者发送来的通知,并在通知后被调用,需要定义一个指向回调方法的委托对象,然后把此对象登记事件发送者中的事件上。

3:如果在事件发生时就不想被通知和调用回掉方法,同样也需要定义一个指向回调方法的委托对象,然后把此对象从事件发送者中的事件上注销。

从上面可以看出,事件中最关键的就是发送者和接受者之间的沟通问题。前面说过了,在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。.NET Framework 定义了一个特殊的类型(Delegate),该类型提供函数指针的功能。通过委托进行登记和注销,从而把发送和接受双方联结起来。

 

5:下面看看是怎么通过委托把两者联系起来的

当编译上面这句时间成员定义时,会产生3个构造方法

// 1:构造一个委托字段
private  MailMsgEventHandler MailMsg  =   null ;

// 2:向这个委托链表上添加委托对象
private  add_MailMsg(MailMsgEventHandler handler)
{
   MailMsg 
= (MailMsgEventHandler)Delegate.Combine(MailMsg,handler)
}


// 3:从这个委托链表上移除委托对象
private  remove_MailMsg(MailMsgEventHandler handler)
{
  MailMsg 
= (MailMsgEventHandler)Delegate.Remove(MailMsg,handler)
}

第一个构造是一个委托类型的字段。这个字段引用的是一个委托链表的首部,链表中包含了那些希望在事件发生时被通知的委托对象。也就是在事件接受者中定义的指向回掉方法的委托对象。一开始这个链表是空的。而后两个构造方法是允许委托对象登记和注销事件的方法。他们通过add_,remove_前缀来命名此方法。调用这些方法时会向链表上添加或移除委托对象。在他们的内部也都是调用System.Delegate的Combine和Remove方法。

在程序中我们见到的却是:


mm.MailMsg 
+= new  MailManager.MailMsgEventHandler(FaxMsg);

mm.MailMsg 
-= new  MailManager.MailMsgEventHandler(FaxMsg);


因为C#编译器对事件提供了内置支持,所以会自动把他转换为上面的add和remove方法。对于那些不支持+=,-=的语言,可以直接调用上面的构造方法。而C#中则要求我们使用这2个操作符,而不允许直接调用方法。

最后要注意的是,只要一个对象仍然登记有另一个对象的事件,该对象就不可能执行垃圾收集。如果我们的类型实现了IDisposable接口的Dispose方法,,我们应该在内部注销其登记的所有事件。

 

6:显式的构造委托成员

以上演示的是在自定义的类中来定义和使用事件。可以发现,其中最重要的就是通过定义一个委托类型的事件成员把发送和接受者连接起来。上面也谈到了事件成员的3个构造方法。

但在.NET的设计中,控件的事件非常多,如果每个时间都自动生成这3个构造函数,那么会是非常的庞大的代码。这里简单介绍下显式的构造委托成员。


(待继)

VB.NET中的.NET远程处理事件详解 远程对象是.NET Remoting框架中的核心概念。它们是能够在不同应用程序域或不同计算机之间进行通信的对象。远程对象的生命周期包括创建过程和生命周期管理,这是确保远程对象正确初始化和清理的关键。自定义远程对象是扩展.NET Remoting功能的基础,它需要从MarshalByRefObject继承,并且可以自定义远程类的特定行为。 阅读详情

相关推荐

FPGA学习之路—应用程序—原码二位乘法器及Verilog代码分析

FPGA学习之路——原码二位乘法器及Verilog代码分析 原理 原码乘法可以分为原码一位乘和原码二位乘,两者在实现规则上大同小异。原码一位乘每次判断乘数的最低位,对被乘数和部分积进行相应操作。而原码二位乘则是对乘数的低二位进行判断,并执行相关操作。 两位乘数的取值可以有四种可能组合,每种组合对应于以下操作: 00相当于0x,部分积Dresult右移2位,不进行其他运算; 01相当于1x,部分积D...

谦豫 3716

c#中event内幕(add与remove)

代码: public event EventHandler NewMail; C#编译器编译这行代码时,会把它翻译成以下3个构造: //1. 一个被初始化为null的私有委托字段 private EventHandler NewMail = null; //2. 一个允

coolen的专栏 1万+

Pointnet++环境配置+复现

深度学习点云经典网络Pointnet++

weixin_58663121的博客 8075

.NET基础知识快速通关(9)

【.NET】|总结/Edison Zhou本文为第九篇,我们会对.NET的事件相关考点进行基础复习,全文会以Q/A的形式展现,即以面试题的形式来描述。Intro开头事件这一名称对于我们.NET码农来说肯定不会陌生,各种技术框架例如WindowsForm、ASP.NET WebForm都会有事件这一名词,并且所有的定义都基本相同。在.NET中,事件和委托在本质上并没有太多...

farway000的博客 299

电子发票二维码背后的秘密:10分钟看懂校验码、加密字符含义与防伪设计

本文深入解析电子发票二维码的结构与防伪设计,揭示校验码和加密字符的生成原理及验证方法。通过实际案例和技术细节,帮助财务人员理解电子发票的安全机制,提升防伪识别能力,确保税务合规。

weixin_29248611的博客 529

django drf 框架知识点(一)——serializer序列化器_用法全解

【django drf】序列化器:别名设置,全部参数序列化,自定义字段,只读只写,部分更新

qq_59344127的博客 1338

C#学习之事件

    .NET的事件模型是建立在委托的机制上,事件机制可以做到,原生的委托也都可以做到;可以说,事件只是对委托的封装,使得用起来更安全。 在具体的代码里,定义一个委托和定义一个事件的差别仅仅是:定义事件时要前面加一个 event 关键字! 正因为这个关键字,编译器就会为这个被封装了的委托暗地里做很多事情,如原生委托可以直接用new来初始化,可以在委托链绑定了很多方法的时候直接用一个 = ...

weixin_34354945的博客 107

lidar360 V8.0 & lidar360MLS V8.0雷达点云数据处理软件

机载林业 — 基于机载激光雷达点云数据提取一系列森林结构参数(如:高度分位数、叶面积指数、郁闭度等),分割单木并提取单木参数(包括树的位置、树高、胸径、枝下高、冠幅等属性),利用软件的多种回归分析功能可以结合地面调查数据反演森林生物量、蓄积量等功能参数。还可以生成等高线、山体阴影、坡度、坡向、粗糙度等多种产品。分类 — LiDAR360提供多种分类功能,包括地面点分类、模型关键点分类、选择区域地面点分类、机器学习模型分类(可高效地分离建筑、植被、路灯等通用类别)、深度学习模型分类、自定义深度学习分类等。

2403_83796253的博客 5149

get、set、add、remove → (字段、属性)+(委托、事件)

学习完了事件(event),可以得到:事件(event)=委托(deledgate)+增加/移除(add/remove) ——这一点,创建一个事件之后用反编译器(.NET Reflector)可以看见 而之前学习属性可以看成:属性=共有的(public)字段+(get/set) 事件的作用与委托变量一样,知识功能上比委托变量有更多的限制。(1、只能通过+=或-=来绑定方法[也就是事件的...

weixin_30609287的博客 402

CUDA:实现使用cuSolverSP底层API实现Cholesky因式分解(附完整源码)

CUDA:实现使用cuSolverSP底层API实现Cholesky因式分解(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 342

29.Labview界面设计 --- (下篇)自定义控件库、界面布局与外观设计

1.自定义控件外观(自定义控件)1.1 自定义外观库1.2 手动自定义控件外观2. 前面板控件布局方式(控件排布)2.1 模块化控制布局方式2.2 数据采集布局方式3. 前面板外观优化项(背景设计)3.1 前面板背景设计3.2 前面板窗口整理本节第一部分教大家安装一种可以直接用的自定义控件库,第二部分教大家如何自己设计控件并保存调用。

关注我,更多技术问题欢迎私聊~ 4781

VB.NET学习笔记:事件处理及自定义事件

测试环境:windows 7和Microsoft Visual Studio 2015 编程必然要知道事件,比如单击按钮事件,然后编写当事件发生时的处理代码,VB.NET是怎样进行事件处理的呢?可否自定义事件呢?因扩展控件,使其列头增加全选全不选复选框并具备分页功能需要用到自定义事件,详见博文《VB.NET学习笔记:WinForm自定义DataGridView分页组合控件》、《VB.NET学习笔记...

zyjq52uys的博客 2894

具身智能(40):主流 VLA 模型π₀

摘要: π₀是首款专为机器人设计的VLA(视觉-语言-动作)端到端基础模型,通过双阶段训练实现“感知-决策-执行”闭环。其创新点包括:1)FlowMatching技术实现连续平滑动作控制(精度0.3°);2)结合VLM预训练与多机器人实操数据,零样本任务完成率达76.4%,远超同类模型;3)支持模糊指令理解与动态场景适应(如遮挡识别)。开源版本涵盖不同规模模型,适用于工业装配、服务机器人等场景,在延迟(213ms)和稳定性(92%自主恢复率)上显著领先OpenVLA等竞品。

码农17年的博客 510

.NET 事件模型教程

http://blog.joycode.com/percyboy/archive/2005/01/22/43438.aspx.NET 事件模型教程(封面) 很久没发文章了,今天发一篇写了半个多月的教程,限于篇幅无法发布到首页来,目录如下:.NET 事件模型教程(一) 事件、事件处理程序概念 问题描述:一个需要较长时间才能完成的任务 高耦合的实现 事件模型的解决方案,

不经历风雨怎么见彩虹 2785

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

.net高级技术—事件初识

1.事件基于委托,为委托提供了一种发布/订阅机制 。在.NET架构内到处都能看到事件。在Windows应用程序中。Button类提供了CLick()事件。这类事件就是委托。触发Click事件时调用的处理程序方法需要得到定义,而其参数由委托类型定义。 2.下面用一个简单的例子来看看事件的使用 案例:定一个Person类,定一个监听年龄变化的事件,当本命年的时候祝贺一下。触发事件的地方要判断一下是...

qq_33407246的博客 1927

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

《Programming ASP.NET》学习笔记(事件)

事件执行程序有两种模式:线性模式和事件驱动模式。理解ASP.NET的关键是,它是事件驱动模式。线性模式的程序从第一步开始执行,然后执行第二步等,直至所有步骤执行完为止。就本质而言,一旦程序开始执行,在用户或系统的操作下,它将一直运行下去。事件驱动模式的程序是当发生某些事情时进行响应(例如按下了按钮)。多数情况下,事件由用户行为生成,但是由系统触发。在ASP.NET中,对象可以触发事

cloudgamer的专栏 1125

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

ASP.NET页面事件

  19.6  ASP.NET页面事件ASP.NET开发人员一直在服务器端代码中使用各种事件。他们使用的许多事件都与特定的服务器控件相关。例如,如果在终端用户单击Web页面上的一个按钮时,要执行某个操作,就应在服务器端代码中创建一个按钮单击事件,如下所示:    < SPAN>Protected Sub Button1_Click(sender 

1406

ASP.NET Core事件总线:应用内事件通信

在现代Web应用开发中,应用内组件间的松耦合通信是构建可维护、可扩展系统的关键。ASP.NET Core提供了强大的事件总线机制,允许不同组件通过事件进行通信,实现真正的解耦架构。本文将深入探讨ASP.NET Core中的事件总线模式,从基础概念到高级实现。 ## 核心事件机制 ### 应用生命周期事件 ASP.NET Core通过`IHostApplicationLifetime`接口提供...

gitblog_00212的博客 1043

.NET Runtime事件追踪:ETW事件

ETW(Event Tracing for Windows,Windows事件追踪)是Windows操作系统提供的高性能、低开销的事件追踪系统。在.NET Runtime中,ETW事件系统扮演着至关重要的角色,它为开发者和运维人员提供了深入了解运行时内部运作的能力。本文将深入探讨.NET Runtime中的ETW事件机制,包括其架构、实现原理、使用场景以及最佳实践。 ## ETW核心概念 ##...

gitblog_01118的博客 824

ASP.NET中的事件处理

 ASP.NET中的事件处理• 事件概述• ASP.NET服务端事件• ASP.NET服务端添加客户端事件• 通过客户端事件引发服务端事件• 事件使用的最佳实践一、事件概述• Visual Studio 项目很容易被看作一系列顺序执行的过程。事实上,多数程序都是事件驱动的——即执行流程是由外界发生的事件所确定的。• 事件是一个信号,它告知应用程序有重要情况发

GoodSpeed的专栏 991

学习笔记:VB.net动态添加控件数组并传递事件

学习笔记:VB.net动态添加控件数组并传递事件控件数组和事件“中间人”动态添加控件 控件数组和事件 新建一个用户窗体,在定义控件数组时,不能用Withevnets来定义数组 即使可以,为每一个数组成员编写事件也是非常麻烦的,考虑通过一个“中间人”来传递事件 “中间人” 用继承的方法为Button控件增加一些事件、属性和方法 Public Class MyButton Inherits ...

DT217的博客 2535

VB.net学习笔记(七)对象事件的定制

Public Delegate Sub WalkedEventHandler(ByVal distance As Int32) Private mWalkedHandlers As WalkedEventHandler Public Custom Event Walked As WalkedEventHandler AddHandler(ByVal value As WalkedEv

白话魔法师 1万+

dotNet学习笔记-浅谈.Net的事件代理

.Net下的事件驱动机制是建立在委托(Delegate)模型下面的,从字面上来解释Delegate的意思就是代理某一样事务,就像现实生活中的买卖一样,各个商场会从生产商那里取得货物的经销代理权,从而商场只负责商品的加工而不必劳神市场。在.Net里的代理机制也是这样,我只要将一个函数逻辑的使用权交给另外一个逻辑,我就可以将我的精力放在其他的事情上面了,这里的逻辑意思就是代码结构,也可以成为是一段代码

刘博的个人博客 1009

.NET事件传递的实现与事件链问题

BODY, P, TD { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 9pt }H2,H3,H4,H5 { color: #0000FF; font-weight: bold; }H2 { font-size: 13pt; }H3 { font-size: 12pt; }H4 { font-size

HuLihui's Blog 4845

.net事件笔记

关于.net 事件 抄书记录 namespace ConsoleApp1 { class Program { static void Main(string[] args) { Stock stock = new Stock("MSFT"); stock.Price = 120; stock.PriceChanged += stock_PriceChanged;

shixianyiyu5277的博客 273

ASP.NET学习笔记(六)

ASP.NET对象的事件与ASP.NET服务器对象。事件编程,事件执行系统的指令的方式,事件的过程就是;系统或用户触发事件。ASP,NET获取事件执行命令,ASP.NET执行事件,并且将结果返回给用户。事件编程模型,开发人员开发ASP.NETweb系统的编程模型,根据用户所触发的事件来编程事情代码。事件执行位置;浏览器端和服务器端。浏览器端事件执行事件的代码在浏览器端,一般采用javascript

liang_704959721的专栏 1237
上一篇: .NET学习笔记(五) ------类型设计(下)
下一篇: .NET学习笔记(七) ------字符串,枚举类型
cc_net
博客等级 码龄21年 901粉丝 54原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值