.NET Framework中的事件
事件体系结构
引发事件的对象叫做事件源。事件源发布它可以引发的事件。事件的类型总是委托类型,这个委托类型的签名定义了处理该事件的方法的签名。定义事件处理程序方法的对象称为事件接收方。事件接收方预订要在事件源上处理的事件事件接收方提供的事件处理程序方法必须与为该事件预订的方法签名一致。事件源利用多播委托跟踪这些事件处理程序方法。当发生重要情况时,事件源引发事件,当事件引发后,事件源自动利用它的金手委托调用在每个事件接收方上指定的事件处理程序方法。
事件和委托的关系
一个事件(Event)是一个对象发送的一个消息,用来表示一个动作发生了。而一个动作可以被用户操作或者其他程序所触发。触发事件的对象被事件发送者(Event Sender)调用:捕获处理事件的对象被事件接收者(Event Receiver)调用。
在事件通信中,事件的发送者不知道哪个对象或者方法将要去接收/处理发送过去的事件。因而在事件源和事件接收者之间就需要一个中间人存在,这个中间人就叫委托。
在使用事件的有效范围里,委托提供一种机制,在事件引发时为类指示要调用的方法。当事件引发时,使用委托作为被调用方法的指针,修改事件的类就不需要了解作为观测程序的类的任何信息。
定义事件
在连接事件和其处理程序方法之前,需要定义一个其他对象关心的事件。用event关键字和指示方法签名的委托对象来定义事件,这个事件的所有事件处理程序都得遵循该委托对象指示的方法签名。
根据约定,引发事件的行为在OnEventName方法中发生。
{
// 如果为事件注册了处理程序则引发该程序
if (Click != null)
{
Click(this, e);
}
}
先进行检查,以确定存在事件,否则值为null。接着像调用方法一样调用事件来引发它,把对控件或类的this传递给它,指示它作为事件的发送者,把一个EventArgs类的新实例作为第二个参数。
使用事件
声明了事件和它相应的委托之后,希望对事件作出响应的对象就必须为这个事件添加一个事件处理程序。事件处理程序是一个方法,它的签名和与事件关联的委托相匹配,当事件引发的时候被调用。
注意:当指派多个处理程序给一个事件的时候,处理程序的调用次序是没有保证的。因此不要指望处理程序会以一个特定次序出现。
EventHandler与EventArgs
EventHandler是.NET Framework中预定了一个用于事件的委托,它有两个参数:object类型参数以及System.EventArgs类型的参数。Object对象代表了事件发送者,EventArgs对象代表了事件包含的事件数据。
其实所有的事件处理方法都只有这两个参数,惟一不同的是,其他的某些事件处理方法的第二个参数会是System.EventArgs的一个子类,用于自定义一些我们需要的事件参数。
ASP.NET事件模型
ASP.NET的事件驱动是一种基于HTTP协议的技术,在ASP.NET中事件的触发和事件的处理是分别在客户端和服务器端进行的。一个事件在客户端被触发之后,会通过HTTP协议以POST的方式发送到服务器端,而服务器端则通过ASP.NET页面架构来进行相应的处理和反馈。
缓存事件
ASP.NET Framework提供给服务器端事件不是很多,因为事件驱动模型机制的实现是在客户端和服务器端分别实现的,之间需要通过HTTP协议方式来传递事件信息,因而如果频繁地触发各类事件会对整个Web站点产生很大的流量压力(如OnMouseOver事件)。但是,有些事件虽然也会频繁的触发但是必须提供(如Change事件),对于这种情况,ASP.NET Framework提供了一个折衷的办法,就是对于这类事件在触发时,不是立即将事件信息发送到服务器,而是缓存在客户端,等到再一次的事件信息被发送到服务器端时一同发送回去。因此,当这些缓存着的事件以及刚刚被触发的事件在服务器端被接收时,ASP.NET Framework不会按照特定的顺序去解释执行处理这些事件。
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/// <summary>
/// 说明:事件被缓存的示例
/// 作者:文野
/// 联系:stwyhm.cnblogs.com
/// </summary>
public partial class CacheEvent : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// 说明:文本框的TextChanged事件,不会自动引发页面Postback
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
Response.Write("引发了文本框的TextChanged事件。<br />");
}
/// <summary>
/// 说明:下拉框的SelectedIndexChanged事件,不会自动引发页面Postback
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Response.Write("引发了下拉框SelectedIndexChanged事件。<br />");
}
/// <summary>
/// 说明:按钮的Click事件,引发页面Postback
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Button1_Click(object sender, EventArgs e)
{
Response.Write("引发了按钮的Click事件。<br />");
}
}
由上面的示例我们看到,当按钮事件引发Postback时同时被缓存的另两个事件也运行了。