摘要 现在基于.Net的Ajax框架很多,Ajax已经变得很傻瓜化,甚至MS还很狂的说,现在所有的Asp.Net程序员都可以在简历上写会Ajax技术,MS狂妄的资本就是MS的Asp.Net 2.0 Ajax框架。众多的Ajax框架确实给我们开发带来了很多的方便,甚至把Ajax的应用简化到控件拖拉的地步,但这也直接导致了很多人滥用Ajax,只要高兴就套个UpdatePannel,这已经成为很多程序员的习惯,却不知道这样做得到的往往是反效果,增加了服务器的负担。 在写程序的过程中,一些小的Ajax效果我不大喜欢去用Ajax框架来做,为了一点点效果就去动用Ajax框架这个相对庞大的家伙显然有点不明智。很多简单的Ajax效果,利用 ICallbackEventHandler接口 ,加点简单的代码就可以很轻松的完成。下面将演示怎样利用ICallbackEventHandler接口 实现客户端回调,实现 检查用户名是可用 的实例。 效果
实现 既然是利用 ICallbackEventHandler接口来实现,那我们先来了解一下ICallbackEventHandler接口。 ICallbackEventHandler 接口用于指示控件可以作为服务器的回调事件的目标。任何需要接收回调事件的控件都要实现 ICallbackEventHandler 接口。继承这个接口需要实现两个方法 RaiseCallbackEvent和 GetCallbackResult,其中, RaiseCallbackEvent用来处理客户端提交的请求, RaiseCallbackEvente有一个string类型的参数,是客户端提交到服务器端的参数。而 GetCallbackResult方法则负责把服务器端的处理结果返回到客户端。 既然要实现回调功能,客户端当然也少不了要有一个向服务器端发送回调请求的函数。用ClientScriptManager类的GetCallbackEventReference方法可以在页面注册一个回调函数。下面来看看GetCallbackEventReference方法在 MSDN中的解释: 语法: public string GetCallbackEventReference( Control control, string argument string clientCallback string context string clientErrorCallback bool useAsync ) 参数 control 处理客户端回调的服务器 Control。该控件必须实现 ICallbackEventHandler 接口并提供 RaiseCallbackEvent 方法。 argument 从客户端脚本传递给服务器端的一个参数 clientCallback 一个客户端事件处理程序的名称,该处理程序接收成功的服务器端事件的结果 context 启动回调之前在客户端计算的客户端脚本。脚本的结果传回客户端事件处理程序 clientErrorCallback 客户端事件处理程序的名称,该处理程序在服务器端事件处理程序出现错误时接收结果 useAsync true 表示同步执行回调 false 表示异步执行回调 返回值 调用客户端回调的客户端函数的名称。 了解了上面两点以后,我们就开始来实现这个功能。先要修改页面,继承 ICallbackEventHandler接口,以让页面支持回调 public partial class _Default : System.Web.UI.Page ,ICallbackEventHandler 然后我们模拟一个已存在用户的列表,在这里为了简单起见(其实是懒,呵呵),我用了一个string的数组,当然,也可以连接到数据库取得已存在的用户 string[] UserNames = { "LixingTie", "生铁" }; 有了已存在用户以后,让我们来实现 ICallbackEventHandler接口的成员。首先是实现 RaiseCallbackEvent方法处理客户端提交的结果。为了保存 RaiseCallbackEvent方法处理的结果,我声明了一个变量 CallbackResult来保存。 string CallbackResult = null; public void RaiseCallbackEvent(string eventArgument) { if(eventArgument == "生铁猪") throw new Exception("请别进行人身攻击!"); CallbackResult = Array.IndexOf(UserNames, eventArgument) != -1 ? "该帐户已注册" : "未注册用户"; } 这里,在 RaiseCallbackEvent方法中,对客户端提交过来的用户名参数eventArgument进行了判断,如果用户名是 "生铁猪" 的话,就抛出一个导常,这主要是用来测试客户端事件处理服务器端处理出错的情况,这里先不理。如果客户端提交上来的用户不是 "生铁猪" ,则判断用户名是否已存在(用户是否在 UserNames 中, 是否为 "LixingTie", "生铁" 之一),如果存在的话,处理结果为 "该帐户已注册" 否则为 "未注册用户"。 继续实现 ICallbackEventHandler接口 的另一个成员 GetCallbackResult 以把处理结果返回到客户端。 public string GetCallbackResult() { return CallbackResult; } 这个方法的实现就比较简单,就单纯的返回 RaiseCallbackEvent方法的处理结果 CallbackResult; 实现了 ICallbackEventHandler接口 之后,这时我们需要在客户端注册一个向服务器端发送回调请求的函数,我们在页面的Load事件中实现这一步骤 protected void Page_Load(object sender, EventArgs e) { if (Page.Request.Browser.SupportsXmlHttp) { ClientScriptManager cs = Page.ClientScript; string callbackScript = cs.GetCallbackEventReference(this, "GetClientUserName()", "OnCallbackCompleted", null, "OnServerError", true); string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}"; cs.RegisterClientScriptBlock(this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true); } } 先用 ClientScriptManager cs = Page.ClientScript;来获得页页的 ClientScriptManager引用。然后通过 GetCallbackEventReference注册发送回调请求的函数, cs.GetCallbackEventReference(this, "GetClientUserName()", "OnCallbackCompleted", "", "OnServerError", true); 参数一 this 代表处理客户端回调的控件为当前页。 参数二 "GetClientUserName()" 是页面上的一个javascript函数,该函数返回的是用户在TextBox中输入的用户名,用户名将提交到服务器进行判断,GetClientUserName()函数的具体内容将在下面补上。 参数三 "OnCallbackCompleted" 表示接收服务器端事件处理结果的javascript函数为 OnCallbackCompleted 函数。 参数四 null,这个实例不需要用到这个参数,所以给它一个空值。这个参数的具体作用见上面MSDN的解释。 参数五 "OnServerError",这个参数指定了当服务器端处理出错时,由客户端的javascript函数OnServerError()来接收错误信息并处理。在这个实例中,当用户在TextBox里输入 "生铁猪" 的时候服务器端会抛出错误并调用客户端函数OnServerError()处理错误并显示。 参数六 true 表示同步执行这次回调。 GetCallbackEventReference函数将根据参数返回一个string类型的发送回调请求的脚本,我们把这个脚本保存在callbackScript变量中。 string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}"; 这条语句将拼接一个名为CallbackScriptMethod的javascript脚本,然后把回调请求脚本放在这个函数体内。这样做以后就可以在javascript里通过CallbackScriptMethod() 函数引发回调。 cs.RegisterClientScriptBlock(this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true); 这条语句把引发回调的函数 CallbackScriptMethod()发送到客户端。 至于 if (Page.Request.Browser.SupportsXmlHttp)这句是用来检测客户端浏览器是否XmlHttp,因为回调功能使用了XmlHttp,所以,在不支持XmlHttp的浏览器中,这个功能是不能用的。 至此,服务器端的逻辑就已经完成了。后台完整代码如下
代码 点击 + 展开
using System;
using System.Data;
using System.Configuration;
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;![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public partial class _Default : System.Web.UI.Page ,ICallbackEventHandler![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
string CallbackResult = null;![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
string[] UserNames =
{ "LixingTie", "生铁" };![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
protected void Page_Load(object sender, EventArgs e)![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ClientScriptManager cs = Page.ClientScript;
if (Page.Request.Browser.SupportsXmlHttp)![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string callbackScript = cs.GetCallbackEventReference(this, "GetClientUserName()", "OnCallbackCompleted", null, "OnServerError", true);
string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}";
cs.RegisterClientScriptBlock(this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true);
}
else![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
cs.RegisterStartupScript(this.GetType(), "SupportsXmlHttp", "alert('你的浏览器不支持XmlHttp,不能使用回调功能!')",true);
}
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string GetCallbackResult()![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return CallbackResult;
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseCallbackEvent(string eventArgument)![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if(eventArgument == "生铁猪")
throw new Exception("请别进行人身攻击!");
CallbackResult = Array.IndexOf(UserNames, eventArgument) != -1 ? "该帐户已注册" : "未注册用户";
}
}
现在开始,我们来实现页面的界面和客户端的javascript。页面的内容很简单,就一个用来输入用户名的TextBox,一个发起回调的HTML Button,和一个显示信息的SPAN <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="ClientUserName" runat="server"></asp:TextBox> <input id="CheckBtn" type="button" value="检查帐户" οnclick="CheckUserName();" /> <span id="message" style="color:Red;"></span> </div> </form> </body> 现在我们来补全刚刚服务器代码中要用到的javascript。代码如下: <script language="javascript" type="text/javascript"> function GetClientUserName() { return document.getElementById("<%=ClientUserName.ClientID %>").value; } function CheckUserName() { CallbackScriptMethod(); } function OnCallbackCompleted(CallbackResult,context) { document.getElementById("message").innerText = CallbackResult; } function OnServerError(error) { alert("错误信息 " + error); } </script> GetClientUserName为刚刚服务器端代码需要用到的获取用户输入的用户名的函数。通过document.getElementById("<%=ClientUserName.ClientID %>").value;取得Textbox ClientUserName的值。注意这里用的ID是ClientUserName.ClientID而不是直接用ClientUserName,原因是服务器控件的ID和服务器发送到客户端的ID可能会不同。ClientID是获取发送到客户端的ID。 OnCallbackCompleted 是接收服务器端处理结果的函数。 OnServerError 是处理服务器出错的函数。 CheckUserName 是点击检查按钮时候调用的函数,这个函数将调用服务器端生成的引发回调的函数CallbackScriptMethod(),引发回调。 完整的页面代码如下:
可以看到,输入"生铁猪"的时候,除了我们原先定义的错误信息外,后面还符加有一段字符,这段字符具体代表的是什么我不大清楚,我想应该是错误的一些附加信息吧。不知道这样认为对不对,知道的朋友请告诉我一下,谢谢。 总结 感觉上,.Net带给我们的便利还是很多的,我们只需要编写少量代码就可以实现这个回调功能。但是我们在享受.Net带给我们的便利的同时,也千万别忘了这种便利是建立在损耗性能的前题下的。个人认为,在web编程的过程中,如果不是在后台需要访问的元素都尽量用HTML控件去完成,少点用服务器控件。因为服务器控件都是经过封装的,每个控件都有它自己的生命周期,需要经过初始化,加载状态,Render等等步骤最后才输出为我们在客端看到的元素,这必定是要损耗服务器性能的。 程序之路还在摸索学习之中,如果我有什么错误的地方,请各位大家多多指正,谢谢。 相关 源项目下载:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"> <title>CallbackTest</title> <script language="javascript" type="text/javascript"> function GetClientUserName() { return document.getElementById("<%=ClientUserName.ClientID %>").value; } function CheckUserName() { CallbackScriptMethod(); } function OnCallbackCompleted(CallbackResult,context) { document.getElementById("message").innerText = CallbackResult; } function OnServerError(error) { alert("错误信息 " + error); } </script></head><body> <form id="form1" runat="server"> <div> <asp:TextBox ID="ClientUserName" runat="server"></asp:TextBox> <input id="CheckBtn" type="button" value="检查帐户" οnclick="CheckUserName();" /> <span id="message" style="color:Red;"></span> </div> </form></body></html> 到这里这个例子就完成了。我们可以在IE中看一下效果。(注:调试客户端错误处理的时候请不要在Debug模式下调试页面,因为在Debug模式下抛出异常的话VS会自动切换到代码中检查代码。右击页面选"在浏览器中查看"就行了。)