ASP.NET Web 服务器控件事件模型
更新:2007 年 11 月
ASP.NET 中有一个重要功能,允许您通过与客户端应用程序中类似的、基于事件的模型来对网页进行编程。举一个简单的例子,例如,可以向 ASP.NET 网页中添加一个按钮,然后为该按钮的 Click 事件编写事件处理程序。尽管这种情况在仅使用客户端脚本(在动态 HTML 中处理按钮的 onclick 事件)的网页中很常见,但 ASP.NET 将此模型引入到了基于服务器的处理中。
与传统 HTML 页或基于客户端的 Web 应用程序中的事件相比,由 ASP.NET 服务器控件引发的事件的工作方式稍有不同。导致差异的主要原因在于事件本身与处理该事件的位置的分离。在基于客户端的应用程序中,在客户端引发和处理事件。但是,在 ASP.NET 网页中,与服务器控件关联的事件在客户端(浏览器)上引发,但由 ASP.NET 页在 Web 服务器上处理。
对于在客户端引发的事件,ASP.NET Web 控件事件模型要求在客户端捕获事件信息,并通过 HTTP POST 将事件消息传输到服务器。页必须解释该 POST 以确定所发生的事件,然后在要处理该事件的服务器上调用代码中的相应方法。
ASP.NET 处理捕获、传输和解释事件等任务。当您在 ASP.NET 网页中创建事件处理程序时,通常无需考虑捕获事件信息并使其可用于您的代码的方式。创建事件处理程序的方式与您在传统的客户端窗体上的创建方式大体相同。尽管如此,ASP.NET 网页中的事件处理仍有一些您应该注意的地方。
服务器控件和页的事件组
由于大多数 ASP.NET 服务器控件事件要求到服务器的往返行程才能进行处理,因此这些事件可能会影响页的性能。因此,服务器控件仅提供有限的一组事件,通常仅限于 Click 类型事件。一些服务器控件支持 Change 事件。例如,CheckBox Web 服务器控件在用户单击该框时引发服务器代码中的 CheckedChanged 事件。一些服务器控件支持更抽象的事件。例如,Calendar Web 服务器控件引发 SelectionChanged 事件,该事件是 Click 事件的更抽象版本。
对于服务器控件,不支持经常发生(并且是在用户不知道的情况下引发)的事件,如 onmouseover 事件。ASP.NET 服务器控件仍然可以为这些事件调用客户端处理程序,后文中的 ASP.NET Web 服务器控件事件模型将对此进行说明。
控件和页本身还会在每个处理步骤引发生命周期事件,例如 Init、Load 和 PreRender。您可以在应用程序中利用这些生命周期事件。例如,在页的 Load 事件中,可以设置控件的默认值。
事件参数
基于服务器的 ASP.NET 页和控件事件遵循事件处理程序方法的标准 .NET Framework 模式。所有事件都传递两个参数:表示引发事件的对象,以及包含任何事件特定信息的事件对象。第二个参数通常是 EventArgs 类型,但对于某些控件而言是特定于该控件的类型。例如,对于 ImageButton Web 服务器控件,第二个参数是 ImageClickEventArgs 类型,它包括有关用户单击位置的坐标的信息。
![]() |
---|
页事件(例如,该页的 Load 事件)可以接受两个标准参数,但不会通过这些参数传递值。 |
服务器控件中的回发和非回发事件
在服务器控件中,某些事件(通常是 Click 事件)会导致页被立即回发到服务器。HTML 服务器控件和 Web 服务器控件(如 TextBox 控件)中的 Change 事件不会立即导致页被发送。它们在下一次发生发送操作时引发。
![]() |
---|
如果浏览器支持,验证控件可以使用客户端脚本检查用户输入,而无需到服务器的往返行程。有关详细信息,请参见 在 ASP.NET 网页中验证用户输入。 |
回发页之后,会引发该页的初始化事件(Page_Init 和 Page_Load),然后处理控件事件。如果您对于页事件处理方面的知识没有比较透彻的了解,则不要创建依赖于按特定顺序引发的 Change 事件的应用程序逻辑。有关详细信息,请参见 ASP.NET 页生命周期概述。
如果它对于您的应用程序很有用,则您可以进行指定,让 Change 事件导致页发送。支持 Change 事件的 Web 服务器控件包括 AutoPostBack 属性。当该属性为 true 时,控件的更改事件会导致页立即发送,而不等待 Click 事件。例如,默认情况下,CheckBox 控件的 CheckedChanged 事件不会导致该页被提交。但是,如果将控件的 AutoPostBack 属性设置为 true,则一旦用户单击该复选框,该页便会立即被发送到服务器进行处理。
![]() |
---|
为了使 AutoPostBack 属性正常工作,用户的浏览器必须设置为允许运行脚本。这在大多数情况下是默认设置。但是,有些用户出于安全性方面的原因禁止运行脚本。有关详细信息,请参见 ASP.NET 网页中的客户端脚本。 |
转发的事件
诸如 Repeater、DataList、GridView、FormView 和 DetailsView 控件之类的 Web 服务器控件可以包含自身引发事件的按钮控件。例如,GridView 控件中的每一行都可以包含由模板动态创建的一个或多个按钮。
与每个按钮各自引发一个事件不同,来自嵌套控件的事件被转发到容器控件。然后,容器通过能够使您发现引发原始事件的单独控件的参数,反过来引发一个一般事件 ItemCommand。通过响应此单个事件,可以避免不必要地为子控件编写单独的事件处理程序。
ItemCommand 事件包括两个标准事件参数,即引用事件源的对象和包含特定于事件的信息的事件对象。
![]() |
---|
GridView、DataList 和其他数据控件支持作为转发事件的特殊情况的其他事件,例如,EditCommand、DeleteCommand 和 UpdateCommand。 |
对于按钮,可以使用 CommandArgument 属性向事件处理程序传递一个用户指定的字符串,以帮助您确定引发该事件的按钮。例如,在 DataList 控件中,按钮引发 ItemCommand 事件。可以将每个按钮的 CommandArgument 属性设置为一个不同的值 - 可能一个按钮的值为“ShowDetails”,而另一个按钮的值为“AddToShoppingCart”- 随后在事件处理程序中捕获这些值。
将事件绑定到方法
一个事件就是一条消息,例如“某按钮已被单击”。在应用程序中,必须将消息转换成代码中的方法调用。事件消息与特定方法(即事件处理程序)之间的绑定是通过事件委托来实现的。有关更多信息,请参见事件和委托。
在 ASP.NET 网页中,如果控件是以声明(标记)的方式在页中创建的,则您不需要显式地对委托进行编码。事件绑定可以通过各种方法来完成,具体方法取决于要绑定的事件以及所使用的编程语言。有关详细信息,请参见如何:在 ASP.NET 网页中创建事件处理程序。
绑定控件事件
对于在页上声明的控件,可以通过在控件的标记中设置属性 (Attribute/Property) 将事件绑定到方法。下面的代码示例演示如何将 ASP.NET Button 控件的 Click 事件绑定到名为 ButtonClick 的方法。
<asp:button id="SampleButton" runat="server"
text="Submit" onclick="ButtonClick" />
如果页已编译,ASP.NET 将查找名为 ButtonClick 的方法,并确认该方法具有适当的签名。该方法接受两个参数,一个是 Object 类型,另一个是 EventArgs 类型。然后 ASP.NET 可以自动将事件绑定到方法。
在 Visual Basic 中,可以选择在事件处理程序声明中使用 Handles 关键字将事件绑定到方法,如下面的代码示例所示:
Private Sub ButtonClick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles SampleButton.Click
绑定页事件
ASP.NET 页会引发诸如 Init、 Load、 PreRender 等生命周期事件。默认情况下,可以使用 Page_事件名称的命名约定将页事件绑定到方法。例如,若要为页的 Load 事件创建处理程序,可以创建名为 Page_Load 的方法。编译时,ASP.NET 将查找基于此命名约定的方法,并自动执行事件与方法之间的绑定。可以对 Page 类公开的任何事件使用 Page_事件名称的约定。
![]() |
---|
页事件处理方法不需要任何参数。 |
如果您愿意,可以显式地创建处理程序。基于方法命名约定的页事件的自动绑定由名为 AutoEventWireup 的页属性控制。默认情况下,此属性设置为 true,并且 ASP.NET 将执行前面介绍的自动查找和绑定。此外,也可以将该属性 (Property) 设置为 false,方法是在 @ Page 指令中添加 AutoEventWireup=false 属性 (Attribute)。然后可以创建具有任意名称的方法并显式地将这些方法绑定到页事件。在 Visual Basic 中,可以使用 Handles 关键字,如下面的代码示例所示:
Sub MyPageLoad(sender As Object, e As EventArgs) Handles MyBase.Load
AutoEventWireup 属性的缺点是它要求页事件处理程序具有特定的、可预测的名称。这就限制了在命名事件处理程序方面的灵活性。
![]() |
---|
如果包括页事件的显式绑定,请确保将 AutoEventWireup 属性设置为 false,以便方法不会意外地被调用两次。 |
动态控件的显式绑定
如果通过使用标记声明控件来创建控件,可以使用属性(如 onclick)将事件绑定到方法。在 Visual Basic 中,则应当使用 Handles 关键字。如果要动态(通过代码)创建控件,则不能使用上述任意方法,因为编译器在编译时没有对控件的引用。
在这种情况下,必须使用显式的事件绑定。在 Visual Basic 中,可以使用 AddHandler 语句将动态创建的控件中的事件绑定到现有的方法。在 C# 中,可以创建委托并将它与控件的事件关联。下面的代码示例演示如何将名为 ButtonClick 的方法绑定到按钮的 Click 事件:
Dim b As New Button
b.Text = "Click"
AddHandler b.Click, AddressOf ButtonClick
Placeholder1.Controls.Add(b)
Button b = new Button;
b.Text = "Click";
b.Click += new System.EventHandler(ButtonClick);
Placeholder1.Controls.Add(b);
响应 ASP.NET 服务器控件中的客户端和服务器事件
本主题讨论了如何处理在服务器代码中引发的事件。控件将元素呈现在浏览器中,并且这些元素还可以引发客户端事件。您可以使用客户端脚本来处理这些事件。使用客户端脚本,可以向 ASP.NET 服务器控件中添加鼠标和键盘事件的处理。有关更多信息,请参见 ASP.NET 网页中的客户端脚本和如何:向 ASP.NET Web 服务器控件添加客户端脚本事件。
应用程序和会话事件
除了页和控件事件之外,ASP.NET 还为您提供多种处理生命周期事件的方法,这些事件可以在应用程序启动或停止时引发,也可以在单个用户的会话开始或停止时引发,包括如下:
对于所有对应用程序的请求,都将引发应用程序事件。例如,当请求应用程序中的任何 ASP.NET 网页或 XML Web services 时,会引发 HttpApplication 对象 (Application_BeginRequest) 的 BeginRequest 事件。该事件使您可以初始化资源,这些资源将用于对应用程序的每一请求。对应的事件,即 HttpApplication 对象的 EndRequest 事件 (Application_EndRequest),使您可以关闭或释放用于该请求的资源。
会话事件类似于应用程序事件(会话事件有 Start 和 End 事件),但会话事件由应用程序内每个唯一的会话引发。当用户第一次从应用程序请求页时开始一个会话,当应用程序显式关闭该会话或当会话超时时该会话结束。
说明:
Session_End 事件在任何情况下都不会引发。有关详细信息,请参见 End。
您可以在 Global.asax 文件中为这些类型的事件创建处理程序。有关详细信息,请参见 IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述 和 Global.asax 语法。