C#事件


1.2      事件

事件是C#语言内置的语法,可以定义和处理事件,为使用组件编程提供了良好的基础。

1.16.1       事件驱动

Windows操作系统把用户的动作都看作消息,C#中称作事件,例如用鼠标左键单击按钮,发出鼠标单击按钮事件。Windows操作系统负责统一管理所有的事件,把事件发送到各个运行程序。各个程序用事件处理函数响应事件,这种方法也叫事件驱动。

C#语言使用组件编制Windows应用程序。组件本质上是类。在组件类中,预先定义了该组件能够响应的事件,以及对应的事件函数(不是程序员编制的事件处理函数),该事件发生,将自动调用相应的预定义事件函数。例如,按钮类中定义了单击事件Click和单击事件函数。一个组件可能定义了多个事件,应用程序中不必也没必要响应所有的事件,而只需响应其中很少事件,程序员编制相应的事件处理函数,用来完成需要响应的事件所应完成的功能。现在的问题是,第一,如何把程序员编制的事件处理函数和组件类中预先定义的事件函数联系起来。第二,如何使不需响应的事件无动作。这是本节要解决的问题。

1.16.2       事件的声明

在C#中,事件首先代表事件本身,例如按钮类的单击事件,同时,事件还是代表类型引用变量,可以代表程序员编制的事件处理函数,把事件和事件处理函数联系在一起。下面的例子定义了一个Button组件,这个例子不完整,只是说明问题。实际在C#语言类库中已预定义了Button组件,这里的代码只是想说明Button组件中是如何定义事件的。例子如下:

public delegate void EventHandler(object sender,EventArgs e);//代表类型声明

//EventHandler变量可以代表没有返回值,参数为(object sender,EventArgs e)的函数

public class Button:Control//定义一个按钮类Button组件

{…//按钮类Button其它成员定义

public event EventHandler Click;//声明一个事件Click,是代表类型引用变量

protected void OnClick(EventArgs e)//Click事件发生,自动触发OnClick方法

{   if(Click!=null)//如果Click已代表了事件处理函数,执行这个函数

Click(this,e);

}

public void Reset()

{   Click=null;}

}

在这个例子中,Click事件发生,应有代码(未列出)保证自动触发OnClick方法。Click是类Button的一个事件,同时也是代表类型EventHandler的引用变量,如令Click代表程序员编制的事件处理函数,Click事件发生时,将执行程序员编制的事件处理函数,完成程序员希望完成的工作。如果Click为null,OnClick函数将不做任何事情。下节将介绍用何种语句使Click代表程序员编制的事件处理函数。

1.16.3       事件的预订和撤消

在随后的例子中,我们声明了一个使用Button类的登录对话框类,对话框类含有两个按钮:OK和Cancel按钮。

public class LoginDialog: Form//登录对话框类声明

{   Button OkButton;

Button CancelButton;

public LoginDialog()//构造函数

{   OkButton=new Button();//建立按钮对象OkButton

//下条语句令Click代表OkButtonClick方法,注意+=的使用

OkButton.Click+=new EventHandler(OkButtonClick);

CancelButton=new Button();//建立按钮对象CancelButton

CancelButton.Click += new EventHandler(CancelButtonClick);

}

void OkButtonClick(object sender, EventArgs e)//程序员编制的事件处理函数

{…//处理OkButton.Click事件的方法,完成程序员希望完成的工作

}

void CancelButtonClick(object sender, EventArgs e)

{…//处理CancelButton.Click事件的方法,完成程序员希望完成的工作

}

}

在例子中建立了Button类的两个实例,单击按钮事件Click通过如下语句和事件处理方法联系在一起:OkButton.Click+=new EventHandler(OkButtonClick),该语句的意义是使OkButton.Click代表事件处理方法OkButtonClick,这样只要Click事件被触发,事件处理方法OkButtonClick就会被自动调用。撤消事件和事件处理方法OkButtonClick的联系采用如下语句实现:OkButton.Click-=new EventHandler(OkButtonClick),这时,OkButton.Click就不再代表事件处理方法,Click事件被触发,方法OkButtonClick就不会被调用了。务必理解这两条语句的用法。使用Visual Studio.Net集成环境可以自动建立这种联系,在自动生成的代码中包括这两条语句。

1.3      索引指示器

在C#语言中,数组也是类,比如我们声明一个整型数组:int[] arr=new int[5],实际上生成了一个数组类对象,arr是这个对象的引用(地址),访问这个数组元素的方法是:arr[索引],在数组类中,使用索引访问元素是如何实现的呢?是否可以定义自己的类,用索引访问类中的数据成员?索引指示器(indexer)为我们提供了通过索引方式方便地访问类的数据成员的方法。

首先看下面的例子,用于打印出小组人员的名单:

using System

class Team

{   string[] s_name = new string[2];//定义字符串数组,记录小组人员姓名

public string this[int nIndex]//索引指示器声明,this为类Team类的对象

{   get//用对象名[索引]得到记录小组人员姓名时,调用get函数

{   return s_name[nIndex];

}

set//用对象名[索引]修改记录小组人员姓名时,调用set函数

{   s_name[nIndex] =value;//value为被修改值

}

}

}

class Test

{   public static void Main()

{   Team t1 = new Team();

t1[0]="张三";

t1[1]="李斯";

Console.WriteLine("{0},{1}",t1[0], t1[1]);

}

}

显示结果如下:张三,李斯

1.4      命名空间

一个应用程序可能包含许多不同的部分,除了自己编制的程序之外,还要使用操作系统或开发环境提供的函数库、类库或组件库,软件开发商处购买的函数库、类库或组件库,开发团队中其它人编制的程序等。为了组织这些程序代码,使应用程序可以方便地使用这些程序代码,C#语言提出了命名空间的概念。命名空间是函数、类或组件的容器,把它们按类别放入不同的命名空间中,命名空间提供了一个逻辑上的层次结构体系,使应用程序能方便的找到所需代码。这和C语言中的include语句的功能有些相似,但实现方法完全不同。

1.18.1       命名空间的声明

用关键字namespace声明一个命名空间,命名空间的声明要么是源文件using语句后的第一条语句,要么作为成员出现在其它命名空间的声明之中,也就是说,在一个命名空间内部还可以定义命名空间成员。全局命名空间应是源文件using语句后的第一条语句。在同一命名空间中,不允许出现同名命名空间成员或同名的类。在声明时不允许使用任何访问修饰符,命名空间隐式地使用public修饰符。例子如下:

using System;

namespace N1//N1为全局命名空间的名称,应是using语句后的第一条语句

{   namespace N2//命名空间N1的成员N2

{   class A//在N2命名空间定义的类不应重名

{   void f1(){};}

class B

{   void f2(){};}

}

}

也可以采用非嵌套的语法来实现以上命名空间:

namespace N1.N2//类A、B在命名空间N1.N2中

{   class A

{   void f1(){};}

class B

{   void f2(){};}

}

也可以采用如下格式:

namespace N1.N2//类A在命名空间N1.N2中

{   class A

{   void f1(){};}

}

namespace N1.N2//类B在命名空间N1.N2中

{   class B

{   void f2(){};}

}

1.18.2       命名空间使用

如在程序中,需引用其它命名空间的类或函数等,可以使用语句using,例如需使用上节定义的方法f1()和f2(),可以采用如下代码:

using N1.N2;

class WelcomeApp

{   A a=new A();

a.f1();

}

using N1.N2实际上是告诉应用程序到哪里可以找到类A。请读者重新看一下1.2.1节中的例子。

1.5      非安全代码

在C和C++的程序员看来,指针是最强有力的工具之一,同时又带来许多问题。因为指针指向的数据类型可能并不相同,比如你可以把int类型的指针指向一个float类型的变量,而这时程序并不会出错。如果你删除了一个不应该被删除的指针,比如Windows中指向主程序的指针,程序就有可能崩溃。因此滥用指针给程序带来不安全因素。正因为如此,在C#语言中取消了指针这个概念。虽然不使用指针可以完成绝大部分任务,但有时在程序中还不可避免的使用指针,例如调用Windows操作系统的API函数,其参数可能是指针,所以在C#中还允许使用指针,但必须声明这段程序是非安全(unsafe)的。可以指定一个方法是非安全的,例如:unsafe void F1(int * p){…}。可以指定一条语句是非安全的,例如:unsafe int* p2=p1;还可以指定一段代码是非安全的,例如:unsafe{ int* p2=p1;int* p3=p4;}。在编译时要采用如下格式:csc 要编译的C#源程序 /unsafe。

最新文章

  1. kettle运行spoon.bat时找不到javaw文件
  2. 软件工程(FZU2015)赛季得分榜,第三回合
  3. MFC 线程使用
  4. apache 配置用户级目录
  5. webstorm 主题设置 皮肤设置
  6. asp.net学习
  7. 不要怂,就是GAN (生成式对抗网络) (二)
  8. telnet 不是内部或外部 命令
  9. WF4.0——升级技能:托付应用
  10. Unity 3D 之贪吃蛇 Text 心得 & Audio
  11. JAVA设计模式之---工厂模式
  12. 转:Kafka 客户端TimeoutException问题之坑
  13. Java入门(二):注释和基本数据类型
  14. Java对象与JSON互相转换jsonlib以及手动创建JSON对象与数组——(二)
  15. SSM框架搭建总结(2)
  16. DNS解析原理和流程
  17. MySQL字符存储:charset-unicode-sets
  18. 【Linux笔记】在后台执行scp,实现服务器间无密码文件拷贝。
  19. DirectStream、Stream的区别-SparkStreaming源码分析02
  20. css 积累1

热门文章

  1. gRPC入门
  2. 深入理解Android
  3. 进击的Python【第九章】:paramiko模块、线程与进程、各种线程锁、queue队列、生产者消费者模型
  4. Eight POJ - 1077 HDU - 1043 八数码
  5. ACM牛人博客
  6. 模拟 hihoCoder 1177 顺子
  7. 影响TCP连接寿命的因素
  8. jmeter正则表达式提取器使用
  9. 一个页面通过iframe,获取另一个页面的form
  10. http的请求与响应-----content-type