文章目的:作者(初学者)在学习c#的过程中,对事件、委托及其中的“object sender,EventArgs e”一直感觉理解不透,因此在网上找了一些资料,学习并整理出了该篇笔记,希望能将自己的心得记录下来作为积累。限于能力且是初学,有错误的地方还请大家批评指正。

注意:该笔记中有部分内容摘自网上的参考资料(如《浅析c#中的object sender和EventAgs e》),并非作者原创,仅限学习交流,特此声明!

一. 委托与事件

      委托与事件是一对相互关联的概念。委托是一种引用类型,可通过声明委托变量,并将其初始化为某个匹配的函数来实现对该函数的引用。事件可以使类或对象向其他类或对象通知发生的相关事情,以使其他类或对象为此做出响应。灵活的事件处理要求将事件的响应分派给相应的事件处理程序(或称事件处理函数、事件处理方法),而C#中事件处理程序通常都是委托实现的。

二. 委托

  1. 定义

    委托其实是一种引用类型,它通过声明一个委托类型的变量,并通过将该变量初始化一个与该委托具有相同返回值类型和形参列表的函数引用,来实现所谓的对函数的引    用。

  2. 声明方式

    modifiers(opt)      delegate           return-Type        identifier         fomal-parameter-listopt))

            修饰符(可选)        委托关键字        返回值类型             标识符              (形参列表(可选)

            Public                    delegate           double                DataProcess     (double x, double y)

  3. 使用步骤

    1)声明委托,指定其返回值类型和形参列表;

     2)定义与委托具有相同返回值类型和形参列表的函数;

     3) 声明委托类型的变量,并将该委托变量初始化为步骤2)中所定义的与该委托具有相同返回值类型和形参列表的函数引用.

  4. 使用举例

 public delegate double DataProcess(double x, double y);//声明委托DataProcess,指定其返回值类型和形参列表
class A
{
  public static double Multiply(double x, double y); //定义与委托具有相同返回值类型和形参列表的函数Multiply()
{
  return x*y;
}
  DataProcess dataProcess = new DataProcess(Multiply);//定义了委托之后,声明该委托类型的变量dataProcess,接着把这个变量初始化为与委托具有相同返回值类型和 //形参列表的函数引用Multiply
9 }

三. 事件

  1. 定义

    1)发起者:引发事件的类或对象;

    2) 订户:处理(或称“响应”)事件的类或对象;

    3) 事件处理程序:订户提供的一些代码,用于在事件被引发时执行(事件处理程序可位于发起者所在的类,也可位于其他类);

    4) 订阅:在发起者引发事件后,执行订户的事件处理程序(即将事件处理程序绑定到事件);

    5) 事件:事件由发起者引发,由订户订阅,事件被引发后开始执行订阅该事件的由订户所提供的事件处理程序;

  2. 声明方式

    modifiers(opt)         event              Type                     identifier   

    修饰符(可选)          委托关键字         类型                      标识符    

    Public                      event               EventHanlder       Click

四。 事件的分类及其使用步骤

  这里将事件分为两种:1.NetFrameWork类库中已经为我们封装好的事件;2.我们自定义的事件。下面分别说明这两种事件的使用步骤,并给出代码示例:

  1.NetFrameWork类库中封装好的事件的使用步骤

    注意:在.NET Framwork类库中,事件是基于EventHandler(委托祖类)和EventArgs(事件数据祖类)两个基类的。

    1)定义委托

      委托的定义用于指定订阅该事件的事件处理程序(或事件处理方法、事件处理函数)的返回值类型及形参列表(此处以backgroundWorker组件为例);     

             public   delegate   void   DoWorkEventHandler ( object sender,  DoWorkEventArgs e); 
 
       a. 返回值类型:void
      b. 参数1:object sender:
       
是一个对象,其实是一个对象引用,这里的事件是对象backgroundWorker1的事件,这个对象指的就是backgroundworker1。(backgroundWorker1是B ackgroundWorker类的一个实例)。
      c. 参数2:DoWorkEventArgs e:
是一个包含事件数据的对象,用于传递事件的细节,DoWorkEventArgs是一个包含事件数据的类,它继承自包含事件数据的基类EventArgs;      注意:委托的返回值类型和形参列表根据自己的需要定义(包括命名),只要事件处理方法的返回值和参数与之匹配即可。此外委托并不需要与事件位于同一个类或 命名空间中,它可以位于其他类或命名空间,在.Net Framwork的类库中就是这样,自定义事件可根据需要安排。
   2)定义事件
     
 public  event  DoWorkEventHandler  DoWork;

      该事件位于BackgroundWorker类中,所以调用时为this.backgroundWorker1.DoWork,该事件在RunWorkerAsync()函数中引发,该函数也位于         BackgroundWorker类中。

    3)定义监听事件函数(监听事件函数用于在满足一定条件时引发事件)

     事件DoWork的监听事件函数是RunWorkerAsync(),该函数已经由.NET在BackgroundWorker类中定义,我们直接用就可以。
      

   4)定义事件处理函数 
   
private void Process(object sender, DoWorkEventArgs e)
{
Console.writeln(“the event has processed!”);
}

    注意:要求事件处理函数与委托具有匹配的返回值类型和参数列表。

    5)为事件添加事件处理函数

     
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(Process);

    以上便是.net类库封装的事件的使用过程,但是事件处理函数的添加一般在组件(或控件)的属性中设置即可,另外委托、事件和监听事件函数.NET Framework类     库已经为我们定义好,直接用就可以,我们唯一需要做的就是编写事件处理函数,我们可以在事件处理函数中写入事件发生时我们想做的事情。

  2.自定义事件使用步骤(这里以一个类来监听客户端键盘输入事件为例)

    1)定义委托

      

public delegate void UserRequest(Object sender, EventArgs e);

      注意:参数Object用来传递事件的发生者,EventArgs用来传递事件的细节(该例暂时没用到)。

    2)定义事件 (步骤1)中的委托类型

      

public event UserRequest OnUserRequest;

    3)定义监听事件函数

      监听事件函数用于在满足一定条件时引发事件,监听事件函数对于在.NET Framwork类库中封装的事件已经为我们定义好了,无需我们自己定义。而这里我们需要自    己定义,此函数相当于事件使用步骤1中的RunWorkerAsync()函数

//该函数不断要求用户从键盘输入字符,如果输入结果为“h”,则引发OnUserRequest事件,事件的引发者是本身(this,即该类(或该类实例化对象)),事件细节无(没有传递任何参数给E//ventArgs实例),我们给这个类起名为UserInputMonitor。
public void run()
{
bool finished = false;
do
{
if (Console.ReadLine() == "h")
{
OnUserRequest(this,new EventArgs());//如果用户键盘输入为“h”,则引发事件
}
} while (!finished);
}  

    4)定义事件处理程序(这里将该函数定义在客户端类(Client类)中)

      首先实例化UserInputMonitor类:

UserInputMonitor monitor = new UserInputMonitor();

      然后定义事件处理程序

private void ShowMessage(object sender, EventArgs e)
{
Console.WriteLine("haha");//如果用户输入的h,则打印“haha”
}

    5)将事件处理程序绑定到事件(或称订阅事件)

      这里将其写到Client的构造函数里

Client(UserInputMonitor m)
{
m.OnUserRequest += new UserInputMonitor.UserRequest(this.ShowMessage);
}

      接下来创建客户端并开始监听事件

new Client(monitor);//将事件处理方法绑定到事件OnUserRequest
monitor.run();

  该自定义事件的全部代码如下所示(c#控制台程序)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication2
{ class Client
{
//构造函数
Client(UserInputMonitor m)
{
m.OnUserRequest += new UserInputMonitor.UserRequest(this.ShowMessage);//订阅事件
} public static void Main(string[] args)
{
UserInputMonitor monitor = new UserInputMonitor();
new Client(monitor);//将事件处理方法绑定到事件OnUserRequest
monitor.run();
} private void ShowMessage(object sender, EventArgs e)
{
Console.WriteLine("haha");
}
} class UserInputMonitor
{
public delegate void UserRequest(Object sender, EventArgs e);//定义委托 public event UserRequest OnUserRequest;//定义此委托类型的事件 public void run()
{
bool finished = false;
do
{
if (Console.ReadLine() == "h")
{
OnUserRequest(this,new EventArgs());//如果用户键盘输入为“h”,则事件发生
}
} while (!finished);
} }
}

 五. 进一步研究C#中的预定义事件处理机制

   可能大家发现在C#中有些事件和前面的似乎不太一样。例如:

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)//事件处理程序
{ }
this.textBox1.KeyPress+=newSystem.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);//将事件处理程序绑定到事件KeyPress

      这里使用了KeyPressEventArgs而不是EventArgs作为参数。这里使用了KeyEventHandler委托,而不是EventHandler委托。KeyPressEventArgs是EventArgs的派生类,而KeyEventHandler的声明如下 :

public delegate void KeyEventHandler( object sender,KeyEventArgs e);

    是参数为KeyEventArgs的委托。那为什么KeyPress事件要这么做呢,我们可以从两个类的构造函数来找答案。

public EventArgs();
public KeyPressEventArgs(char keyChar);

    

    这里的keyChar是什?是用来传递我们按下了哪个键的。我在KeyEventArgs中又发现了如下属性,进一步证明了我的理论。

public char KeyChar { get; }

    下面举个具体的例子,加深一下理解:我们也定义一个EventArgs(类似KeyEventArgs)取名MyEventArgs,定义一个构造函数public MyEventArgs(char keyChar),同样我们也设置相应的属性。完成代码如下(控制台程序):

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication2
{
class MyEventArgs:EventArgs//定义了一个事件类
{
private char keyChar; public MyEventArgs(char keyChar)//构造函数
{
this.keyChar = keyChar;
} public char KeyChar
{
get{return keyChar;}
}
} class UserInputMonitor
{
public delegate void UserRequest(object sender, MyEventArgs e);//定义委托
public event UserRequest OnUserRequest;//定义此委托类型的事件 public void Run()//监听事件函数
{
bool finished = false;
do
{
string inputString = Console.ReadLine();
if(inputString != "")
{
OnUserRequest(this,new MyEventArgs(inputString[]));//引发异常
}
}while(!finished);
}
} class Client
{
static void Main(string[] args)
{
UserInputMonitor monitor = new UserInputMonitor();
new Client(monitor);
monitor.Run(); } Client(UserInputMonitor m)
{
m.OnUserRequest += new UserInputMonitor.UserRequest(this.ShowMessage);//将监听事件函数绑定到事件处理函数 } public void ShowMessage(object sender, MyEventArgs e)
{
Console.WriteLine("捕捉到:{0}",e.KeyChar);
}
}
}

关于c#中委托与事件的一些理解的更多相关文章

  1. C#中委托和事件的区别实例解析

    这篇文章主要介绍了C#中委托和事件的区别,并分别以实例形式展示了通过委托执行方法与通过事件执行方法,以及相关的执行流程与原理分析,需要的朋友可以参考下 本文实例分析了C#中委托和事件的区别,分享给大家 ...

  2. c#中委托和事件(转)

    C# 中的委托和事件 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真 ...

  3. c#中委托和事件(续)(转)

    本文将讨论委托和事件一些更为细节的问题,包括一些大家常问到的问题,以及事件访问器.异常处理.超时处理和异步方法调用等内容. 为什么要使用事件而不是委托变量? 在 C#中的委托和事件 中,我提出了两个为 ...

  4. 转载:C#中委托、事件与Observer设计模式

    原文地址 http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx 感谢博主分享! 范例说明 假设 ...

  5. C#中委托和事件

    目 录 将方法作为方法的参数 将方法绑定到委托 更好的封装性 限制类型能力 范例说明 Observer 设计模式简介 实现范例的Observer 设计模式 .NET 框架中的委托与事件 为什么委托定义 ...

  6. C#中委托和事件的区别

    大致来说,委托是一个类,该类内部维护着一个字段,指向一个方法.事件可以被看作一个委托类型的变量,通过事件注册.取消多个委托或方法.本篇分别通过委托和事件执行多个方法,从中体会两者的区别. □ 通过委托 ...

  7. CS中委托与事件的使用-以Winform中跨窗体传值为例

    场景 委托(Delegate) 委托是对存有某个方法的引用的一种引用类型变量. 委托特别用于实现事件和回调方法. 声明委托 public delegate int MyDelegate (string ...

  8. c#中委托和事件区别

    委托和事件相同的功能 class Dem5 { public Action deHandler; public event Action eveHa; public Dem5() { deHandle ...

  9. C#中委托、事件和回调函数的理解

    在C#中我们经常会碰到事件,尤其是在WPF或者WinForm中,窗体加载.或者点击一个按钮,都会触发事件.实际上,事件是对委托的封装.如果不进行封装,让委托暴露给调用者,调用者就可以把委托变量重新引用 ...

随机推荐

  1. .Net工程师面试笔试宝典

    .Net工程师面试笔试宝典 传智播客.Net培训班内部资料 http://net.itcast.cn 这套面试笔试宝典是传智播客在多年的教学和学生就业指导过程中积累下来的宝贵资料,大部分来自于学员从面 ...

  2. GBK还是UTF-8? Eclipse连接TFS的编码之痛!encoding, encoding, encoding…

    在中文Windows操作系统上安装Eclipse或MyEclipse,默认会将Eclipse的编码设置为GBK,与操作系统的默认编码保存一致. 在这种默认设置下,在Eclipse新增的文件不会自动被团 ...

  3. Python 定制类 特殊方法

    1.特殊方法 定义在class中 不需要直接调用,python的某些函数或操作符会自动的调用对应的特殊方法. 如定义了person类,使用print p 语句打印person类的实例时,就调用了特殊方 ...

  4. django系列6--Ajax06 使用插件,Sweet-Alert插件

    使用SweetAlert插件 GitHub上的下载链接 下载完成后放入django项目静态目录下,在html文件中引入静态文件,下面是script部分 $(".btn-danger" ...

  5. java—在dbutils中处理事务与不确定条件的查询(46)

    在dbutils中处理事务        事务是指用户的一次操作.这一次操作有可能是一个表,也有可能是多个表,也有可能是对一个表的多次操作. 只要是: 1:对数据数据库进行多次操作. 2:多个表,还是 ...

  6. 20165219 Exp1 PC平台逆向破解

    20165219 Exp1 PC平台逆向破解 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串 ...

  7. 【OCP-12c】CUUG 071题库考试原题及答案解析(17)

    17.(7-11) choose twoView the Exhibit and examine the structure of ORDER_ITEMS and ORDERS tables.You ...

  8. luoguP5074 Eat the Trees

    https://www.luogu.org/problemnew/show/P5074 插头 $ dp $ 入门题 如果你还不会插头 $ dp $ 请右转 洛谷插头dp题解 虽然是入门题但还是逃不过分 ...

  9. NOI2019省选模拟赛 第五场

    爆炸了QAQ 传送门 \(A\) \(Mas\)的童年 这题我怎么感觉好像做过--我记得那个时候还因为没有取\(min\)结果\(100\to 0\)-- 因为是个异或我们肯定得按位考虑贡献了 把\( ...

  10. Jzoj 初中2249 蒸发学水(并查集)

    题目描述 众所周知,TerryHu 是一位大佬,他平时最喜欢做的事就是蒸发学水. 机房的位置一共有n 行m 列,一开始每个位置都有一滴学水,TerryHu 决定在每一个时刻选择 一滴学水进行蒸发,直到 ...