c#事件

简介
任何编写过图形用户界面(GUI)软件的开发人员都熟悉事件处理编程,当用户与GUI控制进行交互时(例如点击表格上的按钮),作为上述事件的反应,就会执行一个或多个方法。没有用户的参与,事件也可能执行。事件处理程序是对象的方法,是根据应用程序中发生的事件而执行的。为了理解.Net框架下的事件处理模式,我们需要理解代理的概念。
C#中的代理
C#中的代理允许我们将一个类中的方法传递给其他类的对象。我们能够将类A中的方法m封装为一个代理,传递给类B,类B能够调用类A中的方法m,静态和实例方法都可以传送。C++软件开发人员应该对这一概念非常熟悉,在C++中,开发人员能够以参数的形式使用函数指针将函数传递给同理个类或其他类中的方法。代理的概念是在Visulal J++中引入的,然后又被带到了C#中。在.Net框架中C#的代理是以从System.Delegate中继承的类的形式实现的。使用代理需要4个步骤:
1、定义一个输入参数与要进行封装的方法完全相同的代理对象。
2、定义所有输入参数与在第1步中定义的代理对象相同的方法。
3、创建代理对象,并与希望封装的方法进行连接。
4、通过代理对象调用封装的方法。
下面的C#代码通过实现一个代理、4个类举例说明了上面的4个步骤:
using System;
//步骤1:定义一个具有被封装方法输入参数的代理对象
public delegate void MyDelegate(string input);
//步骤2:定义与定义的代理对象具有相同输入参数的方法
class MyClass1{
public void delegateMethod1(string input){
Console.WriteLine("This is delegateMethod1 and the input to the method is {0}",input);
}
public void delegateMethod2(string input){
Console.WriteLine("This is delegateMethod2 and the input to the method is {0}",input);
}
}
//步骤3:创建代理对象,插入方法
class MyClass2{
public MyDelegate createDelegate(){
MyClass1 c2=new MyClass1();
MyDelegate d1 = new MyDelegate(c2.delegateMethod1);
MyDelegate d2 = new MyDelegate(c2.delegateMethod2);
MyDelegate d3 = d1 + d2;
return d3;
}
}
//步骤4:通过代理调用被封装的方法。
class MyClass3{
public void callDelegate(MyDelegate d,string input){
d(input);
}
}
class Driver{
static void Main(string[] args){
MyClass2 c2 = new MyClass2();
MyDelegate d = c2.createDelegate();
MyClass3 c3 = new MyClass3();
c3.callDelegate(d,"Calling the delegate");
}
}

C#中的事件处理程序
C#中的事件处理程序是一个带有特定输入参数的代理,如下所示:
public delegate void MyEventHandler(object sender, MyEventArgs e);

上面定义中的第一个参数(sender)指定了发生事件的对象,第二个参数(e)存储着在事件处理程序中要用到的数据。MyEventArgs类是继承EventArgs类得来的,EventArgs类是MouseEventArgs、ListChangedEventArgs等更专业化的类的基础类。对于GUI事件,我们可以使用这些特定的EventArgs类的对象,而无需自己创建特定的EventArgs类。然而,对于非GUI事件而言,我们仍然需要创建自己的特定的EventArgs类,存储希望向代理对象传递的数据。我们可以通过继承EventArgs类创建自己特定的EventArgs类:
public class MyEventArgs EventArgs{
public string m_myEventArgumentdata;
}
在事件处理程序中,代理对象的调用需要用到event关健字,如下所示:
public event MyEventHandler MyEvent;
下面我们将建立二个类,体会.Net框架中事件处理机制的工作原理。在对代理的讨论的第二个步骤中,要求我们定义与定义的代理有完全相同的输入参数的方法。在我们的例子中,类A将提供事件处理程序(与代理对象具有相同输入参数的方法。),它将创建代理对象(对代理讨论中的第三步)并安装事件处理程序。类A然后会将代理对象传递给类B。当类B中有事件出现时,它就会执行类A中的事件处理程序方法。
using System;
//步骤1:创建代理对象
public delegate void MyHandler1(object sender,MyEventArgs e);
public delegate void MyHandler2(object sender,MyEventArgs e);
//步骤2:创建事件处理程序方法
class A{
public const string m_id="Class A";
public void OnHandler1(object sender,MyEventArgs e){
Console.WriteLine("I am in OnHandler1 and MyEventArgs is {0}", e.m_id);
}
public void OnHandler2(object sender,MyEventArgs e){
Console.WriteLine("I am in OnHandler2 and MyEventArgs is {0}", e.m_id);
}
//步骤3:创建代理,安装事件处理程序,并向启动事件的对象注册。
public A(B b){
MyHandler1 d1=new MyHandler1(OnHandler1);
MyHandler2 d2=new MyHandler2(OnHandler2);
b.Event1 +=d1;
b.Event2 +=d2;
}
}
//步骤4:通过代理调用封装的方法。
class B{
public event MyHandler1 Event1;
public event MyHandler2 Event2;
public void FireEvent1(MyEventArgs e){
if(Event1 != null){
Event1(this,e);
}
}
public void FireEvent2(MyEventArgs e){
if(Event2 != null){
Event2(this,e);
}
}
}
public class MyEventArgs EventArgs{
public string m_id;
}
public class Driver{
public static void Main(){
B b= new B();
A a= new A(b);
MyEventArgs e1=new MyEventArgs();
MyEventArgs e2=new MyEventArgs();
e1.m_id ="Event args for event 1";
e2.m_id ="Event args for event 2";
b.FireEvent1(e1);
b.FireEvent2(e2);
}
}

C#中的GUI事件处理
Windows Forms(支持GUI应用程序的.NET框架)中的事件处理使用.NET事件处理模式。我们下面将应用这种模式编写一个简单的应用程序,该应用程序有一个继承自System.Windows.Forms.Form类的MyForm类。如果仔细地研究一下代码和其中的三行注释,就会发现其实我们无须定义代理和使用event关健字调用这些代理,因为我们已经可以使用GUI控制(表格、按钮等)的事件(鼠标点击等),代理就是System.EventHandler。当然了,我们仍然需要定义方法,创建代理对象(System.EventHandler),并在代理对象中安装方法,一旦有事件发生,方法就会开始执行。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

public class MyForm Form{
private Button m_nameButton;
private Button m_clearButton;
private Label m_nameLabel;

private Container m_components = null;

public MyForm(){
initializeComponents();
}
private void initializeComponents(){
m_nameLabel=new Label();
m_nameButton = new Button();
m_clearButton = new Button();

SuspendLayout();

m_nameLabel.Location=new Point(16,16);
m_nameLabel.Text="Click NAME button, please";
m_nameLabel.Size=new Size(300,23);

m_nameButton.Location=new Point(16,120);
m_nameButton.Size=new Size(176, 23);
m_nameButton.Text="NAME";
//创建代理,并安装方法,将代理捆绑在按钮的Click事件上
m_nameButton.Click += new System.EventHandler(NameButtonClicked);

m_clearButton.Location=new Point(16,152);
m_clearButton.Size=new Size(176,23);
m_clearButton.Text="CLEAR";
//创建代理,并安装方法,将代理捆绑在按钮的Click事件上
m_clearButton.Click += new System.EventHandler(ClearButtonClicked);

this.ClientSize = new Size(292, 271);
this.Controls.AddRange(new Control[] {m_nameLabel,m_nameButton,m_clearButton});
this.ResumeLayout(false);
}
//定义输入参数与代理完全相同的方法
private void NameButtonClicked(object sender, EventArgs e){
m_nameLabel.Text="My name is john, please click CLEAR button to clear it";
}
private void ClearButtonClicked(object sender,EventArgs e){
m_nameLabel.Text="Click NAME button, please";
}
public static void Main(){
Application.Run(new MyForm());
}
}

结束语
Java和Smalltalk等其他的面向对象的编程语言中都没有代理的概念,这一概念是在C#中新引进的,它源自于C++和J++。我希望上面的讨论使第一次使用面向对象的编程语言时就使用C#语言的编程人员能够弄明白代理的概念。如果使用Visual Studio IDE作为C# GUI的开发环境,无需编写代码就能够将代理中的方法与由GUI控制生成的事件(例如用鼠标点击按钮等)连接在一起,当然了,我们还是应当知道这是怎么回事

时间: 2024-10-30 12:32:41

c#事件的相关文章

总结Selenium WebDriver中一些鼠标和键盘事件的使用

在使用 Selenium WebDriver 做自动化测试的时候,会经常模拟鼠标和键盘的一些行为.比如使用鼠标单击.双击.右击.拖拽等动作:或者键盘输入.快捷键使用.组合键使用等模拟键盘的操作.在 WebDeriver 中,有一个专门的类来负责实现这些测试场景,那就是 Actions 类,在使用该类的过程中会配合使用到 Keys 枚举以及 Mouse. Keyboard.CompositeAction 等类. 其次,在实际测试过程中,可能会遇到某些按键没办法使用 Actions.Keys 等类来

HTML5 Canvas捕获用于游戏开发的键盘、鼠标和触摸事件

学习如何处理键盘和鼠标事件,如何阻止 Web 浏览器的默认事件行为,以及如何向游戏对象的某种逻辑表示传播事件.此外,还将学习如何处理 iPhone 和 iPad 等移动设备上与设备无关的(device-agnostic)输入. 令拥有 Flash 或 Silverlight 背景的开发人员感到惊讶的是,为 HTML5 Canvas 编写的应用程序在处理用户输入方面并没有什么特立独行之处.实质上,从启用了 JavaScript 的 Web 浏览器诞生之初开始,HTML 用户输入就涉及到使用内置于浏

frame-求救。为什么键盘监听事件不响应了。。

问题描述 求救.为什么键盘监听事件不响应了.. mport java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; impor

ie bho 插件:如何获得浏览器滚动条变化事件

问题描述 ie bho 插件:如何获得浏览器滚动条变化事件 我已经写了一个简单的bho. 目的是知道浏览器的滚动条是否滚动. DISPID_DOCUMENTCOMPLETE事件可以获取. DISPID_HTMLWINDOWEVENTS2_ONSCROLL 事件不能获得. class部分: class ATL_NO_VTABLE Chellobho : public CComObjectRootEx, public CComCoClass, public IObjectWithSiteImpl,

从反射看委托与事件 委托真的是一个类

关于委托与事件,网上介绍得非常之多,在此不再赘述,本人最近需要捣鼓一些委托,因而对委托进行一 定的寻根究底,故用反射把委托的成员揪出来,且看如下代码: delegate void DelegateDemo(); static event DelegateDemo delHandle; static void Main() { delHandle += new DelegateDemo(MyDelegate_delHandle); MemberInfo[] mis = delHandle.GetT

异常处理:android中添加按钮事件,出现NullPointerException

问题描述 异常处理:android中添加按钮事件,出现NullPointerException 解决方案 在maincsactivity的oncreate的72行找,有没有对象为null 解决方案二: 对象为空,要么你的按钮对象还没初始化,要么点击代码里有空对象,你调试一下便知 解决方案三: 空指针异常,没什么难找的,Debug一下即可很快找到: 解决方案四: 空指针异常,按钮对象没有初始化 解决方案五: 可能你声明了一个View,但是你没有findViewById,或者findViewById

救命啊!鼠标事件问题

问题描述 问题:怎么让鼠标事件穿透控件?比如:PictureBox1里面有个PictrueBox2,一样大小,那么如何让鼠标事件穿过PicturBox2,来到PictureBOx1 解决方案 解决方案二:你是想让一次点击执行两个事件吗?可以吧两次的事件都写在上面的控件的事件中解决方案三:在处理PictureBox2的事件时发送相应的消息到PictureBox1.解决方案四:哪个触发事件没关系,看你想操作谁就行了解决方案五:说错这种奇葩的功能还不如说说你的需求你要做什么

C#委托和事件

委托和事件 .NET Framework 还可以广泛地将委托用于事件处理任务,如 Windows 或 Web 应用程序中的按钮 Click 事件.Java 中的事件处理通常通过实现自定义侦听器类完成,而 C# 开发人员则可以利用委托处理事件.事件的声明类似于具有委托类型的字段,区别在于事件声明前面有 event 关键字.事件通常被声明为 public,但允许使用任何可访问性修饰符.下面的示例演示了 delegate 和 event 的声明. C#  =复制代码 // Declare the de

asp.net-关于Gridview_rowupdating事件出错

问题描述 关于Gridview_rowupdating事件出错 protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e) { int ID = Convert.ToInt32(GridView1.DataKeys[e.RowIndex].Value.ToString()); string Pass = ((TextBox)(GridView1.Rows[e.RowIndex].Cells[4].C

Activity是如何接收到touch事件的(窗口与用户输入系统)

在<浮窗开发之窗口层级>这片文章中,开篇提出了三个问题: 窗口层级关系(浮窗是如何"浮"的)? 浮窗有哪些限制,如何越过用户授权实现浮窗功能? Activity是如何接收到touch事件的? 前两个问题在前两篇文章中已经分析,在这篇文章中我们以第三个问题为切入点,简单分析一下窗口与用户输入的关系. Touch事件是如何分发到Activity上来的? 正常的思路是直接去寻找Activity 的dispatchTouchEvent方法,我们看看Activity的dispatch