ASP.NET 服务器控件事件模型

与传统的客户端窗体中的事件或基于客户端的 Web 应用程序中的事件相比,由 ASP.NET 服务器控件引发的事件的工作方式稍有不同。导致差异的主要原因在于事件本身与处理该事件的位置的分离。

在基于客户端的应用程序中,在客户端引发和处理事件。另一方面,在 Web 窗体页中,与服务器控件关联的事件在客户端引发,但由 ASP.NET 页框架在 Web 服务器上处理。

对于在客户端引发的事件,Web 窗体控件事件模型要求在客户端捕获事件信息,并且通过 HTTP 发送将事件消息传输到服务器。此页框架必须解释该发送以确定所发生的事件,然后在要处理该事件的服务器上调用代码中的适当方法。有关更多信息,请参见 ASP.NET 服务器控件中的事件

Web 窗体控件事件模型

ASP.NET 实际上处理所有捕获、传输和解释事件的机制。当您在 Web 窗体页中创建事件处理程序时,无需考虑如何捕获事件信息并使其可用于您的代码的机制,即可执行事件处理程序的创建。而且您创建事件处理程序的方式与您在传统的客户端窗体上的创建方式大体相同。虽然如此,Web 窗体页中的事件处理仍有一些您应该注意的方面。

内部事件集

因为大多数 Web 窗体事件要求到服务器的往返过程以进行处理,所以这些事件可能影响窗体的性能。因此,服务器控件仅提供一组有限的内部事件(通常仅限于 Click 类型事件)。某些服务器控件支持 onchange 事件的特殊版本,该事件在控件的值发生更改时被引发。例如,CheckBox Web 服务器控件在用户单击框时引发更改事件。对于服务器控件,不支持经常发生的事件(并且可能在用户不知道的情况下引发),例如 onmouseover 事件。

注意   某些服务器控件支持更高级别的事件的集合。例如,Calendar Web 服务器控件引发 SelectionChanged 事件,该事件是 Click 事件的更抽象的版本。

事件参数

Web 和 HTML 服务器控件事件遵循事件处理程序方法的标准 .NET Framework 模式。所有事件都传递两个参数:表示引发事件的对象的对象,以及包含任何事件特定信息的事件对象。第二个参数通常是 System.EventArgs 类型,但对于某些控件而言是特定于该控件的类型。例如,对于 ImageButton Web 服务器控件,第二个参数是 ImageClickEventArgs 类型,这包括有关用户所单击处坐标的信息。

Web 服务器控件中的回发和非回发事件

在 Web 服务器控件中,某些事件(通常是 Click 事件)会导致将窗体回发到服务器。HTML 服务器控件和 Web 服务器控件(例如 TextBox 控件)中的更改事件将被捕获,但不会立即导致发送。而是由控件缓存这些事件,直到下一次发生发送。然后当在服务器上再次处理该页时,引发和处理所有挂起的事件。

注意   如果浏览器支持它,验证控件可以使用客户端脚本检查用户输入,而无需到服务器的往返过程。有关详细信息,请参见 Web 窗体的用户输入验证简介

在服务器页处理期间,首先处理事件,处理时没有特定的顺序。当处理完所有更改事件后,处理导致发送窗体的 Click 事件。

注意   如果您不是对页事件处理方面的知识有着透彻的了解,则不应创建依赖于按特定顺序引发的更改事件的应用程序逻辑。有关更多信息,请参见回发事件示例

可以指定更改事件导致窗体发送。支持更改事件的 Web 服务器控件包括 AutoPostBack 属性。当该属性为真时,控件的更改事件导致立即发送窗体,而不等待 Click 事件。例如,默认情况下,CheckBox 控件的 CheckedChange 事件不会导致该页被提交。但是,通过将该控件的 AutoPostBack 属性设置为 true,可以指定当用户单击复选框时,立即将该页发送到服务器进行处理。

注意   为了使 AutoPostBack 属性正确工作,用户的浏览器必须设置为允许脚本撰写。这在大多数情况下是默认设置。但是,有些用户出于安全性方面的原因禁用了脚本撰写。有关详细信息,请参见 ASP.NET 服务器控件和浏览器功能

冒泡事件

诸如 RepeaterDataListDataGrid 控件之类的 Web 服务器控件可以包含自身引发事件的按钮 (Button) 控件。例如,DataGrid 控件中的每一行可以包含由模板动态创建的一个或多个按钮。

与单独引发一个事件的每个按钮不同,来自嵌套控件的事件是“冒泡的”,也就是说,这些事件将发送到容器。该容器通过使您可以发现引发该原始事件的单独控件的参数,反过来引发称作 ItemCommand 的一般事件。通过响应此单个事件,可以避免不必要地为子控件编写单独的事件处理程序。

ItemCommand 事件包括两个标准事件参数,即引用事件源的对象和包含特定于事件的信息的事件对象。

注意   DataGridDataList Web 服务器控件支持附加事件,例如 EditCommandDeleteCommandUpdateCommand,它们是冒泡事件的特殊事例。

对于按钮,可以使用 CommandArgument 属性向事件处理程序发送一个用户指定的字符串,以帮助您确定引发该事件的按钮。例如,在一个 DataList 控件中,按钮引发 ItemCommand 事件。您可以将每个按钮的 CommandArgument 属性设置为不同的值,有可能一个按钮的值为“ShowDetails”而另一个按钮的值为“AddToShoppingCart”,随后在该事件处理程序中捕获这些值。

Web 窗体页中的事件委托

一个事件就是一个消息,实际上就是类似于“某按钮已被单击”的消息。在应用程序中,需要该消息被翻译成代码中的方法调用,如“Button1_Click”。事件消息和特定方法(即事件处理程序)之间的绑定是通过事件委托来实现的。有关更多信息,请参见事件和委托

在 Web 窗体页中,通常无需对委托进行显式编码。如果使用 Visual Studio 中的 Web 窗体设计器,该设计器将生成自动将事件绑定到方法的代码。在 Visual Basic 中,可使用事件处理程序声明中的 Handles 关键字来完成此任务,如以下示例所示:

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

在 Visual C# 中,设计器将在页中生成类似于以下内容的显式事件处理程序委托:

private void InitializeComponent()
{   
   this.Load += new System.EventHandler(this.Page_Load);
}

此外,ASP.NET 页框架还支持以自动方式将页事件与方法相关联。如果 Page 指令的 AutoEventWireup 属性被设置为 true(或者如果缺少此属性,因为它默认为 true),该页框架将自动调用页事件,即 Page_InitPage_Load 方法。在这种情况下,不需要任何显式的 Handles 子句或委托。

AutoEventWireup 属性的缺点是它要求页事件处理程序具有特定、可预测的名称。这限制了您在为事件处理程序命名时的灵活性。因此,在 Visual Studio 中,AutoEventWireup 属性在默认情况下设置为 false,设计器会生成用于将页事件绑定到方法的显式代码。

如果将 AutoEventWireup 设置为 true,Visual Studio 将生成用于绑定事件的代码,页框架将自动基于事件的名称来调用事件。这可能会导致在该页运行时两次调用相同的事件代码。因此,当在 Visual Studio 中操作时,应尽量使 AutoEventWireup 设置为 false

响应 ASP.NET 服务器控件中的客户端和服务器事件

在很大程度上,您主要会关心在服务器代码中引发的事件。但是,如果对于您的应用程序是适当的,也可以通过编写客户端脚本来处理 ASP.NET 服务器控件的客户端事件。

注意   不能使用 HTML 语法来绑定到 Web 服务器控件的客户端事件,而必须使用代码添加事件绑定属性。有关示例,请参见下表。

例如,您可能具有已转换为 HTML 服务器控件的 HTML 图像按钮元素。通常,在 Web 窗体页中,您将在服务器代码中处理图像按钮的 Click 事件。但是,您可能还想要使用客户端代码在用户将鼠标移到图像上时更改该图像。可以通过为图像按钮的 onmouseover 事件创建客户端脚本来做到这一点。(在此示例中,假设使用支持 HTML 4.0 的浏览器,例如 Microsoft Internet Explorer 4.0 或更高版本。)

注意   在客户端事件处理程序和服务器端事件处理程序具有相同的事件处理程序名称的情况下,总是首先运行客户端事件处理程序,然后运行服务器事件处理程序。但是,允许这种情况出现会导致混乱,因此强烈建议对命名规则进行一些规划。

处理客户端和服务器代码中的 Click 事件

如果要在客户端和服务器上处理事件,有一个事件会给您带来麻烦,它就是客户端 onclick 事件。之所以会出现问题,是因为所有按钮服务器控件(以及其他 AutoPostBack 属性设置为 true 的控件)都会将页提交到服务器。但是,在 HTML 中,只有少数几个控件本来就会提交窗体:

  • HTML 提交按钮 (<INPUT type=submit>),即类型设置为 SubmitImageHtmlInputButton 控件。可以从“工具箱”的“HTML”选项卡中添加此控件。
  • Button Web 服务器控件 (<asp:button>)。

对于其他所有被指定为提交页的控件,会将一个小的客户端脚本写入页中,并在该控件被单击时调用此脚本来提交窗体。因此,这些控件已使用客户端 OnClick 事件来调用此提交脚本。

可以为所有控件创建客户端 OnClick 处理程序,但需要选择使用每种控件的方式。下表总结了针对不同类型的控件采用的策略。

控件 策略
HtmlInputButton,它包括类型设置为 Submit、Reset 或 Image 的 HTML 服务器控件按钮 为该控件在 HTML 语法中包含一项 onclick 属性:
<INPUT Type="Submit" Runat="Server" Value="caption" onclick="clientfunction()"  ...>

在服务器端,这些类型的按钮会引发 ServerClick 事件,而不是简单的 Click 事件。首先会引发客户端事件,然后提交窗体并处理服务器事件。

其他所有 HTML 控件(默认情况下不提交窗体的 HTML 控件) 为该控件在 HTML 语法中包含一项 onclick 属性,并在该属性后添加一个分号 (;):
<INPUT Type="Button" Runat="Server" Value="caption" onclick="clientfunction();"  ...>

这样,在调用客户端提交脚本之前,将首先调用您的函数。

Web 服务器控件,包括按钮 (<asp:button>) 和其他控件(例如 <asp:checkbox> 不能在 HTML 语法中为 Web 服务器控件指定客户端事件,而应在运行时使用如下服务器代码将事件属性添加到该控件中:
Button1.Attributes.Add("onclick", "clientfunction();")
注意   对于 Button Web 服务器控件无需添加分号,因为该控件会自动提交页。

应用程序和会话事件

除了页和控件事件之外,ASP.NET 页框架为您提供了多种使用事件的方法,这些事件可以在应用程序启动或停止时被引发,也可以在单个用户的会话开始或停止时被引发:

  • 对于所有对应用程序的请求,都将引发应用程序事件。例如,当请求应用程序中的任何 Web 窗体页或 XML Web services 时,都将引发 Application_BeginRequest 事件。该事件使您可以初始化资源,这些资源将用于对应用程序的每一请求。相应的 Application_EndRequest 事件使您可以有机会关闭或处置用于该请求的资源。
  • 会话事件类似于应用程序事件(会话事件有 Session_OnStartSession_OnEnd 事件),但会话事件由应用程序内每一唯一的会话引发。当用户第一次从应用程序请求页时开始一个会话,当应用程序显式关闭该会话或当会话超时时该会话结束。

您可以在 Global.asax 文件中为这些类型的事件创建处理程序。有关详细信息,请参见 Global.asax 文件Global.asax 语法

请参见

Web 窗体页中的服务器事件处理 | Global.asax 文件 | Web 窗体状态管理介绍 | 使用 Httpapplication 实例