在谈论主题之前,让我们先简单回顾下事件的基础知识吧!

  我们知道事件有发出(raises)事件的源,即event sender,也有接收事件通知(notifications)的接收者,即event receiver。因此,若要设计事件必须从发送者和接受者两个Object分别着手设计。其中,发送方类型的设计一般有四个步骤:

  1. 定义类型来容纳所有需要发送给事件通知接收者的信息。
  2. 定义事件成员。注意这里事件成员的类型可以是字段或属性,定义成不同的类型,编译生成的代码有较大的不同,需注意。
  3. 定义负责引发事件的方法来通知事件的登记对象。
  4. 定义一个方法将输入转化为期望的事件。注意,如果在发起事件时事件发送者需要传递信息,那么需要定义这个方法,将输入传递给封装的EventArgs对象,然后调用步骤3的方法,并将EventArgs对象传递给该方法。如果不需要传递信息则不需定义该方法,直接调用步骤3中的方法即可。

接收方类型设计一般有三个步骤:

  1. 设计接收方类型的事件处理方法。
  2. 设计接收方类型的注销对事件关注的方法,和步骤3中做的正好相反。
  3. 将发送方类型的实例对象以参数形式传到接收方类型的实例构造器中(或者在接收方类型的实例构造器中new一个发送方类型的实例,实际上WinForm应用中就是这么做的,在Form构造器中new一个button的实例对象),然后将接收方类型中的回调函数登记到发送方的事件成员上。

  好了,基础知识到此结束,不懂的去看书本哈!下面让我们回到正题上,来看看在WinForm窗体应用中,当我们单击窗体上的一个Button之后究竟发生了什么。

  在实际开发窗体应用时,我们一般都是直接将一个Button拖到Form上,然后Visual Studio会为我们新建一个Button实例对象,并设置它的样式。当我们点击按钮之后,会为我们生成如下的代码:

private void button1_Click_1(object sender, EventArgs e)
{ }

  那我们就会想了,这部分代码属于接收方Form窗体对象的事件处理方法。那事件的发送方Button的负责引发(raises)事件的方法在哪里呢?在一开始用C#的事件时,我并没有对此深究,导致一直模模糊糊的,现在让我们一起看下Button的引发事件的方法究竟躲在哪里吧!

  我们在button1_Click_1事件处理方法这里打一个breakpoint,然后运行程序并单击button1按钮。单步执行并查看程序的调用栈,如下图所示。

图1 单步执行程序并查看调用栈

  我们看到,在button1_Click_1事件处理方法调用之前,调用了Control.OnClick方法,我们可以通过反射工具查看它的源代码,如下图所示:

图2 OnClick方法源码

  从上图最后一行代码可以看出OnClick就是Button实际执行的引发(raises)事件的方法。也许你又有疑问了,base.Events[EventClick]是什么东东?其实,它是一个委托类型的list结构,可以容纳一个以上的委托,使用线性搜索算法来查找其中的条目,在委托条目较多时,查找效率会下降。EventClick是一个静态只读key值,通常赋以new Object(),用来索引事件成员(EventHandler类型)。好了,到这里,事件是不是就可以说懂了呢?不,我们还遗忘了一个点,那就是在声明事件成员时,声明成字段和属性有区别么?如果有区别,那区别大吗?下面让我们首先看一下声明成字段的情况。

  

图3 将MyEvent事件成员定义成字段形式。

图4 字段形式事件MyEvent的源代码

  从图3和4可以看到,本质上来看,以字段形式定义的事件成员,编译器compile之后自动生成的add_MyEvent和remove_MyEvent两个方法是线程安全的,这意味着客户端程序每次向事件添加或删除一个委托时,必须先获得lock,这在非多线程开发的情形下加大了开销,毕竟获取和释放lock是一个耗费时间的过程。

图5 将MyCustomEvent事件成员定义成属性形式

图6 属性形式事件MyCustomEvent的源代码

  从图5和6可以看到,以属性方式声明的事件成员,由于我们事先就定义好了add和remove方法的实现(其实这里就是所谓的“显式实现事件”,这样我们就能控制add和remove方法处理回调委托的方式),在编译之后,仅仅是向一个list中加入和删除委托,并没有考虑多线程的情形,因此,在非多线程的开发中效率较高。注意,事件属性的定义语法和一般的get或set访问器属性不同,事件属性定义中使用add和remove方法。

  实际上,我们在Form窗体上拖放一个Button按钮控件时,就是用的属性形式的事件成员定义。如下图7和8所示。

图7 设计器自动生成的绑定Click事件代码

图8 Click事件成员的源代码形式

  以上就是关于点击一个button发生的事情的真相了,客官,您弄懂了么?

各位客官!鼠标点击一个Button之后究竟发生了什么?您知道么?(C#)的更多相关文章

  1. 【代码笔记】iOS-点击一个button,出6个button

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> //加入头文件 #import "DCPathB ...

  2. 微信小程序中 不点击picker 点击一个button 怎么调用picker 弹出选择框

    把按钮放在picker区域里就好了 picker本身就是一个区域 <picker mode = "selector" class='info' bindchange=&quo ...

  3. 从点击Button到弹出一个MessageBox, 背后发生了什么

    思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox. 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究 ...

  4. 从点击Button到弹出一个MessageBox, 背后发生了什么(每个UI线程都有一个ThreadInfo结构, 里面包含4个队列和一些标志位)

    思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox.   这个看似简单的行为, 谁能说清楚它是如何运行起来的,背 ...

  5. [python] 1、python鼠标点击、移动事件应用——写一个自动下载百度音乐的程序

    1.问题描述: 最近百度总爱做一些破坏用户信任度的事——文库金币变券.网盘限速,吓得我赶紧想办法把存在百度云音乐中的歌曲下载到本地. http://yinyueyun.baidu.com/ 可问题是云 ...

  6. jQuery 二级菜单,一次显示一个小类 鼠标点击显示小类

    jQuery 二级菜单,一次显示一个小类 鼠标点击显示小类 本例有另外2个关联案例,演示地址分别为2.php,3.php 演示 XML/HTML Code <div class="ar ...

  7. 每天一个JavaScript实例-铺货鼠标点击位置并将元素移动到该位置

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. 问题:asp.net 点击button按钮调到页面顶部;结果:asp.net点击一个按钮,使页面跳转到本面页上的指定位置

    asp.net点击一个按钮,使页面跳转到本面页上的指定位置 (2011-04-19 16:46:51) 转载▼ 标签: it   最近在做一个项目. 用到标题所说的功能. 实现方法: 1.在aspx中 ...

  9. 【Unity3D基础】让物体动起来①--UGUI鼠标点击移动

    背景 首先还是先声明自己是比较笨的一个人,总是找不到高效的学习方法,目前自己学习Unity3D的方式主要是两种,一种是直接看高质量的源码,另一种是光看不行还要自己动手,自己写一些有代表性的小程序,这也 ...

随机推荐

  1. PDF预览之PDFObject.js总结

    get from:PDF预览之PDFObject.js总结   PDFObject.js - 将PDF嵌入到一个div内,而不是占据整个页面(要求浏览器支持显示PDF,不支持,可配置PDF.js来实现 ...

  2. ES6系列_5之数字操作

    下面是针对ES6新增的一些数字操作方法进行简单梳理. 1.数字判断和转换 (1)数字验证Number.isFinite( xx ) 使用Number.isFinite( )来进行数字验证,只要是数字, ...

  3. Matlab信号处理工具箱函数

    波形产生和绘图chirp 产生扫描频率余弦diric 产生Dirichlet函数或周期Sinc函数gauspuls 产生高斯调制正弦脉冲pulstran 产生脉冲串rectpuls 产生非周期矩形信号 ...

  4. BeanUtils.copyProperties不能copy复杂对象List的解决方式

    需要注意的就是把List拆分,遍历add,然后把list设置到返回对象中 package test.test; import java.util.ArrayList; import java.util ...

  5. 30. Substring with Concatenation of All Words (String; HashTable)

    You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...

  6. XAMPP非本地访问被拒绝解决办法

    问题场景: 本机搭建一个apache服务器,正常访问XAMPP目录下的页面. 手机接入同一wifi,以电脑ip方式访问该目录下的页面:提示:Access Denied Access to the re ...

  7. dnn ubuntu 问题

    http://blog.csdn.net/moshuilangting/article/details/53926622 http://blog.csdn.net/enjoyyl/article/de ...

  8. oracle存储过程和游标参考

    oracle open cursor forhttp://www.itpub.net/thread-1874683-1-1.html

  9. Composer安装和使用 - Windows

    记录windows下安装和使用Composer的方法 1,使用安装程序 这是将 Composer 安装在你机器上的最简单的方法. 下载并且运行 Composer-Setup.exe,它将安装最新版本的 ...

  10. redis集群种类(转)

    原文:http://blog.csdn.net/c295477887/article/details/52487621 关于redis主从.哨兵.集群的介绍网上很多,这里就不赘述了. 一.主从 通过持 ...