首先说下ICallBackEventHandler,这个接口是什么意思,用官方的述语是用于指示控件可以作为服务器的回调事件的目标.
看着这个解释是挺晕的,那我们就慢慢一步一步来理解.
上面提到了回调这个词,那我们是不是想到一个与之很近的在Asp.Net里面很熟悉的词回发.先说下回发.
在 ASP.NET 网页的默认模型中,用户会与页交互,单击按钮或一些其他操作。此时将重新创建页及其控件,并在服务器上运行页代码,且新版本的页被呈现到浏览器,该过程会导致页面的刷新(重新加载),整个页面将在服务端和浏览器客户端中往返一次,并且使用ViewState保存数据,网络消耗流量加大,会降低性能,且会让用户不得不等待处理并重新创建页,这个就是回发.
若要避免丢失客户端状态并且不导致服务器往返的处理开销,可以对 ASP.NET 网页编码,即编写客户端脚本函数(javascript),由其向服务端发送一个http请求,该网页随后会运行其正常生命周期的简化版本,这会启动该页并创建其控件和其他成员,然后调用一个特别标记的方法。该方法执行代码中编写的处理过程,然后向浏览器返回可由另一客户端脚本函数读取的值(字面上整个这句不太理解,求解),在此过程中,该页一直驻留在浏览器中,这个就是回调.
其实从上面的描述来讲,ICallbackEventHandler就是无刷新页面请求(Ajax),只不过不需要用到任何Ajax框架,完全是Asp.Net提供的.
创建以编程方式实现客户端回调除了要实现ICallbackEventHandler接口中的方法外,还需要如下实现
-
一个函数调用帮助器方法,该方法执行对服务器的实际请求。在此函数中,可以执行自定义逻辑,以最先准备事件实参。您可以将字符串作为形参发送给服务器端的回调事件处理程序。
-
另一个函数由处理回调事件的服务器代码的结果调用并接收该结果,同时接受表示该结果的字符串。此函数称为客户端回调函数。
-
第三个函数是执行实际服务器请求的 Helper 函数。当在服务器代码中使用 GetCallbackEventReference 方法生成对此函数的引用时,ASP.NET 将自动生成此函数。
下面看具体实现
JS代码
<script language="javascript" type="text/javascript"> function ReceiveServerDataSuccess(mResults, context) { //客户端执行的方法,回调成功执行的回调函数,下面的方法是接收并处理服务器方法执行的返回结果 MessageResults.innerHTML = mResults; MessageExtra.innerHTML = context; } function ReceiveServerDataError(mResults, context) { //回调失败执行的回调函数,下面的方法是当接收服务器方法处理处理的结果发生异常时调用的方法 MessageResults.innerHTML = mResults; MessageExtra.innerHTML = context; } </script>
后台代码
public partial class WebForm : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler { protected String mResults; protected String validationLookUpStockOrSale = "LookUpStockOrSale"; protected System.Collections.Specialized.ListDictionary catalog; protected void Page_Load(object sender, EventArgs e) { Page.ClientScript.RegisterClientScriptBlock(this.GetType(), validationLookUpStockOrSale, "function LookUpStockOrSale() { " + "var lb = document.forms[0].ListBox1; " + "var product = lb.options[lb.selectedIndex].text; " + @"CallServerMethod(product, ""LookUpStockOrSale"");} ", true); //获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器事件的客户端回调 String cbReference = Page.ClientScript.GetCallbackEventReference(this, "args", "ReceiveServerDataSuccess", "context", "ReceiveServerDataError", false); String callbackScript; callbackScript = "function CallServerMethod(args,context){ " + cbReference + ";}"; Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServerMethod", callbackScript, true); //从服务端注册CallServerMethod脚本 catalog = new System.Collections.Specialized.ListDictionary(); catalog.Add("LookUpStock|mouse", "LookUpStock|mouse"); catalog.Add("LookUpStock|laptop", "LookUpStock|laptop"); catalog.Add( "LookUpSale|keyboard",1); catalog.Add("LookUpSale|monitor",0); ListBox1.DataSource = catalog; ListBox1.DataTextField = "key"; ListBox1.DataBind(); } public void RaiseCallbackEvent(String eventArgument) //处理以控件为目标的回调事件 { string[] argParts = eventArgument.Split('|'); if ((argParts == null) || (argParts.Length != 2)) { mResults = "A problem occurred trying to retrieve stock count."; return; } string product = argParts[0]; Page.ClientScript.ValidateEvent("LookUpButton", validationLookUpStockOrSale); //为注册的客户端的控件和事件进行验证 switch (product) { case "LookUpStock": try { if (catalog[eventArgument] == null) mResults = "Item not found."; else mResults = catalog[eventArgument].ToString() + " in stock."; } catch { mResults = "Can not retrieve stock count."; } break; case "LookUpSale": try { if (catalog[eventArgument] == null) mResults = "Item not found."; else { if (Convert.ToBoolean(catalog[eventArgument])) mResults = "Item is on sale."; else mResults = "Item is not on sale."; } } catch { mResults = "Can not retrieve sale status."; } break; } } public String GetCallbackResult() //定义返回回调方法执行结果的方法 { return mResults; } protected override void Render(HtmlTextWriter writer) { //使用表示生成事件的客户端控件的唯一控件 ID 和事件参数为验证注册事件引用。 Page.ClientScript.RegisterForEventValidation("LookUpButton", validationLookUpStockOrSale); base.Render(writer); } }
1>获取回调引用。会在客户端生成WebForm_DoCallback方法,调用它来达到异步调用。这个方式是微软写的方法,会被发送到客户端
2>注意这里的"ReceiveServerDataSuccess"和"ReceiveServerDataError"两个字符串分别客户端代码中定义的两个javascript函数
3>args表示传递的参数,context表示可以传递的其他信息,也可以设置为空
4>GetCallbackEventReference的方法最后一个参数的意义:true表示执行异步回调,false表示执行同步回调
5>另注意GetCallbackEventReference的参数名args和CallServerMethod参数名args必须保持一致.
6>在客户端要进行要进行某个操作时(在此程序中表示当用户名文本框失去焦点之后)激发CallServerMethod这个客户端方法
7>这个客户端方法是由在Page_Load时由asp.net动态生成的,并向其传递需要的参数args,也可以传递上下文环境参数context
8>args是必选参数,context是可选参数,可用于传递其他信息,是object类型,甚至可以传递this.id或this等,如果没有传递context,则传递null
9>之后就是将CallserverMethod(args,context)中的args参数传递给WebForm_DoCallback('__Page',args,ReceiveServerDataSuccess,context,ReceiveServerDataError,false) 中的args(注:WebForm_DoCallback中的ReceiveServerDataSuccess和ReceiveServerDataSuccess的脚本函数都是在页面第一次初始化的时候就绑定了的)
10>再后传递给服务器端的RaiseCallbackEvent(string args)中的args,从而调用服务器端的RaiseCallbackEvent函数
11>RaiseCallbackEvent执行完毕后,自动执行服务器端的GetCallbackResult函数,执行完毕之后,如果没有异常,就自动执行客户端的ReceiveServerDataSuccess回调函数(回调成功时调用),如果出现异常,则执行客户端的ReceiveServerDataError回调函数(回调失败时调用)
12>ReceiveServerDataSuccess和ReceiveServerDataError才是回调函数,WebForm_DoCallback('__Page',args, ReceiveServerDataSuccess, context, ReceiveServerDataError, false)只是回调,上面提到的context相当于IAsyncResult.AsyncState,可以在ReceiveServerDataSuccess和ReceiveServerDataError函数中捕获,可以用于传递其它的信息
13>WebForm_DoCallback函数其实在第一次初始化页面的时候服务器传给客户端的,大家可以用firebug看下解析过的js代码
html代码:
<div> <asp:ListBox ID="ListBox1" runat="server"></asp:ListBox> <br /> <br /> <input type="button" value="Look Up Stock Or Sale" id="LookUpButton" onclick="LookUpStockOrSale();" /> <br /> Item status: <span id="MessageResults"></span> Item Extra status: <span id="MessageExtra"></span> </div>
更多的信息大家可以去研究MSDN的东东,链接地址给出来
http://msdn.microsoft.com/zh-cn/library/system.web.ui.icallbackeventhandler%28v=vs.90%29.aspx