为自定义服务器控件实现事件,是一个比较复杂的过程。开发人员不仅需要根据上一篇文章中介绍的方法,实现捕获回传事件,而且有时候还需要参与回传数据处理过程。本文将通过典型应用介绍处理回传数据的方法。
1. 实现处理回传数据
在上一篇文章介绍的捕获回传事件过程中,往往都不涉及回传到服务器的控件数据。开发人员主要实现IPostBackEventHandler接口就能够成功捕获事件,并为之定义事件处理程序。然而,有些服务器控件在应用过程中,涉及回传数据的变化等情况。例如,自定义控件是一个输入控件,当用户输入并回传后,可能会由于回传数据的变化而引发一些事件。为了处理以上问题,控件类必须实现IPostBackDataHandler接口。下面列举了接口声明代码。
public interface IPostBackDataHandler{ public bool LoadPostData ( string postDataKey, NameValueCollection postCollection ); public void RaisePostDataChangedEvent ();} |
IPostBackDataHandler接口用于在创建需要由客户端回传到服务器的窗体数据的服务器控件时使用。如上代码所示,该接口包括两个方法,LoadPostData和RaisePostDataChangedEvent。
与实现捕获回传事件类似,仅仅在控件类中实现接口是不完整的。下面总结了为了实现处理回传数据而必须实现的两个要点。
第一、必须在控件呈现中将控件的name的属性值设置为UniqueID。这是由于发生回传后,页框架将在发送的内容中搜索与实现IPostBackDataHandler的服务器控件的UniqueID匹配的值,然后才能调用LoadPostData方法。
第二、控件类必须实现IPostBackDataHandler接口,并实现LoadPostData和RaisePostDataChangedEvent方法。LoadPostData方法用来检查提交给服务器的数据。该方法包含两个参数:postDataKey表示用于识别控件内数据的关键值,postData是提交数据的集合,其采用Key/Value结构便于使用索引名称访问。要访问集合中的控件数据,只要采用如下代码即可:"string nData = postData[postDataKey]; "。在LoadPostData方法中,通过新数据(客户端发送的数据值)与旧数据(先前提交给客户端的数据值)进行比较的结果来确定方法返回值。如果新旧数据相同,则说明数据没有被修改,方法返回值为false;如果新旧数据不同,则表明旧数据已经被客户端修改,方法返回值true。下面是LoadPostData方法的一个简单应用。
public virtual bool LoadPostData(string postDataKey,NameValueCollection postData) { string presentValue = Text; //旧数据 string postedValue = postData[postDataKey];//新数据 //检查新旧数据 if(presentValue.Equals(postedValue) || presentValue == null) { Text = postedValue; return true; } return false; } |
如果LoadPostData方法返回true,.NET框架将自动调用RaisePostDataChangedEvent方法。该方法用信号要求服务器控件对象通知ASP.NET应用程序该控件的状态已更改,控件开发者可以在该方法中定义根据数据变化引发的事件。下面是简单的调用OnTextChanged方法:
public virtual void RaisePostDataChangedEvent() { OnTextChanged(EventArgs.Empty); } |
以上是处理回传数据的实现要点,掌握这些要点对于事件处理具有至关重要的意义。同时,其内容也说明了以下.NET框架处理回传数据的过程:
(1)首先在发送的内容中搜索与实现IPostBackDataHandler的服务器控件的UniqueID匹配的值。
(2)调用LoadPostData方法,并返回bool值。
(3)如果LoadPostData方法返回true,那么调用RaisePostDataChangedEvent方法。
(4)执行RaisePostDataChangedEvent方法中定义的OnEvent方法。
2. 典型应用
下面通过一个典型实例说明处理回传数据的核心过程。创建一个自定义文本框控件WebCustomControl,其文本属性Text因回传而更改。控件在加载回传数据后引发TextChanged事件。控件类源代码如下所示:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace WebControlLibrary{ [DefaultProperty("Text")] [ToolboxData("<{0}:WebCustomControl runat=server></{0}:WebCustomControl>")] public class WebCustomControl : WebControl, IPostBackDataHandler { // 实现Text属性 [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Localizable(true)] public string Text { get { string s = (String)ViewState["Text"]; return ((s == null) ? String.Empty : s); } set { ViewState["Text"] = value; } } //重写控件呈现方法RenderContents protected override void RenderContents(HtmlTextWriter output) { output.AddAttribute(HtmlTextWriterAttribute.Type, "text"); output.AddAttribute(HtmlTextWriterAttribute.Value, Text); output.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID); output.RenderBeginTag(HtmlTextWriterTag.Input); output.RenderEndTag(); } //定义事件对象EventTextChanged private static readonly object EventTextChanged = new object(); #region 实现IPostBackDataHandler 成员 bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection) { //比较初始数据presentValue和回传数据postedValue string postedValue = postCollection[postDataKey]; string presentValue = Text; if (presentValue == null || postedValue != presentValue) { Text = postedValue; return true; } return false; } void IPostBackDataHandler.RaisePostDataChangedEvent() { OnTextChanged(EventArgs.Empty); } #endregion // 实现事件处理程序OnTextChanged private void OnTextChanged(EventArgs eventArgs) { EventHandler textChangedHandler = (EventHandler)Events[EventTextChanged]; if (textChangedHandler != null) { textChangedHandler(this, eventArgs); } } // 为TextChanged实现事件属性结构 public event EventHandler TextChanged { add { Events.AddHandler(EventTextChanged, value); } remove { Events.RemoveHandler(EventTextChanged, value); } } } } |
以上源代码实现了一些重要内容。
(1)控件类必须实现IPostBackDataHandler,由此可使该控件参与回传数据处理。
(2)定义属性Text,其属性值保存在ViewState中。当页面回传时,包含Text属性值的ViewState将被提交到服务器。
(3)重写RenderContents方法,并在该方法中定义控件呈现逻辑。
(4)实现IPostBackDataHandler的方法LoadPostData。比较客户端发送的数据值与先前服务器提交给客户端的数据值是否相同。如果数据相同,说明数据没有被修改,那么返回false;如果数据不同,则表明数据已经被客户端修改,则返回true。
(5)实现IPostBackDataHandler的方法RaisePostDataChangedEvent。如果LoadPostData的返回值为true,则执行该方法,即要求调用OnTextChanged方法。
(6)定义事件属性结构TextChanged。在Events事件委托列表中,为EventTextChanged事件委托对象定义Add和Remove访问器。
(7)定义OnTextChanged方法。
下面是应用自定义服务器控件的Default.aspx源代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register TagPrefix="wcl" Assembly="WebControlLibrary" Namespace="WebControlLibrary" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> void demo1_TextChanged(object sender, EventArgs e) { label1.Text = "您在文本框中输入的是 " + demo1.Text; } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>处理回传数据</title> </head> <body> <form id="form1" runat="server"> <div> <wcl:WebCustomControl ID="demo1" runat="server" OnTextChanged="demo1_TextChanged" /> <asp:Button ID="button1" runat="server" Text="提交" /> <br /> <asp:Label ID="label1" runat="server" Font-Size="small"> </asp:Label> </div> </form> </body> </html> |
在以上代码中,定义了一个WebCustomControl控件,并为该控件定义TextChanged事件的处理方法demo1_TextChanged。该方法要求修改Label控件的Text属性值。效果图如图1和图2所示。
图1 页面初始化效果图 图2 页面提交后的效果图 |
可能某些读者会产生误解,以为上面的实例定义了提交按钮的Click事件的事件处理方法。实际不然。本实例并没有为提交按钮定义Click事件的处理方法,而是通过处理回传数据,并定义WebCustomControl控件的TextChanged事件来完成的。
3、小结
本文针对实现处理回传数据的实现方法进行了介绍。掌握这些内容将为开发出具有高质量的服务器控件打下良好基础。至此,通过三篇文章的介绍,相信读者已经掌握了为自定义服务器控件实现事件的基本方法。在随后的内容中,笔者将继续介绍利用ASP.NET 2.0技术创建服务器控件的其他内容。