开发人员使用JavaScript的一个主要原因就是可以避免回发过程中带来的页面刷新。例如我们可以根据用户的需要使用Treeview控件来展开和折叠相应的数据节点。当你展开一个节点时,该Treeview控件将会利用JavaScript读取服务器上的子节点信息,然后平滑无刷新地插入这些新节点。如果没有使用JavaScript的话,Treeview控件将会因为页面的回发而重新构建。不但用户会发现因页面刷新而带来的延迟,而且页面极有可能回复到原来的状态,即丢失前面所展开的那些子节点信息。对于服务器端来说,因为每次回发的过程中都要处理大量的视图状态(View State)信息,这也会严重影响程序的整体执行性能。
以前我们使用的JavaScript示例几乎都是自包含的,即它们通常是为了完成一些特殊的显示效果(例如弹出一个新的页面窗口),而没有和服务器端代码进行信息的交互。如果你也想构建一个类似的无刷新页面的话,你首先必须调用服务器端的一个特定的方法,等待服务器响应后就会将请求的信息传递到客户端,从而避免了回发这个过程。为了实现这个方案,你首先需要对如何将客户端脚本和服务器端代码进行通讯有个大致的了解。尽管有许多中方法可以实现这两者间的交互(例如调用Web服务),但是由于受到特定的浏览器和平台的限制,它们的实现是还是有一定的难度的。而在ASP.NET 2.0中,引入了一个称为"客户端回调"的功能,利用这个内建的解决方案我们可以轻松实现客户端脚本和服务器端代码间的交互,从而避免了页面因回发带来的频繁刷新。
客户端回调本质上就是指通过前端的客户端脚本向服务器端传递相应的数据参数,服务器端再以接受到的参数进行查询和处理,最后将结果回传到客户端进行显示。虽然这样的过程不是一种创举,但是对于许多开发者来说这在某种思维上还是无法理解的,因为JavaScript的内存管理和.NET CLR的内存管理是不同的进程,而且管理的空间上也截然不同,所以彼此间无法直接参照也没有直接进行交互的方式,而客户端回调却是实现客户端和服务器端进行沟通的方法之一,又因为它是在客户端触发的,所以这就应该是"客户端回调"命名的由来吧!
创建一个简单的客户端回调
为了在ASP.NET中展示一个客户端回调的实例,首先我们将概述客户端回调间的交互过程是如何实现的。下面是基本的步骤:
1. 在某时刻激活一个JavaScript事件,从而触发客户端回调。
2. 触发客户端回调发生后,服务器端的一个方法将被执行。该方法有一个固定的模式――它接受的是一个字符串参数,并且返回的也是一个字符串参数。
3. 一旦页面接受到来自服务器端方法的响应结果后,它就可以利用JavaScript修改一些和用户界面有关的信息(例如显示在页面上显示返回的结果)
对于开发人员来说,底层的交互过程是非常复杂的,ASP.NET则将交互的处理过程进行了抽象化,这样使得开发人员可以直接建立表层的客户端回调,而无需考虑底层的操作是如何实现的。
下面的实例中,页面中放置了一个文本框,一个提交按钮和一个标签。文本框是用来接受用户的输入信息,在单击提交按钮后将把文本框中输入的信息在标签上进行实时的显示。注意,在输入信息后单击提交按钮时,并没有像以前传统的提交方式那样重新对页面进行构建和刷新。图1-1为该实例的效果图。
实例的效果图 实例的效果图 |
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="CallBackExample.aspx.cs" Inherits="CallBackExample" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>客户端回调</title> </head> <body> <form id="form1" runat="server"> <div> 请输入信息:<asp:TextBox ID="txtEnter" runat="server"></asp:TextBox> <input id="btnSubmit" type="button" value="提交" onclick="CallServer(txtEnter,lblShow)"/> <br /> <asp:Label ID="lblShow" runat="server"></asp:Label> </div> </form> </body> </html> |
public partial class CallBackExample : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler {… …} |
using System; using System.Data; using System.Configuration; using System.Collections; 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; public partial class CallBackExample : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler { //定义一个字符串,回调的结果信息将保存在该字符串中 private string result; //引发回调事件处理 public void RaiseCallbackEvent(string eventArgument) { //"eventArgument"为从客户端的JavaScript传递过来的参数 result = "从服务器端返回的内容:" + eventArgument; } //回传回调结果 public string GetCallbackResult() { return result; } } |
编写客户端脚本
客户端脚本主要是用来在服务器端和客户端之间进行信息的交互,就拿本例来说,我们在前面的页面逻辑代码中使用了一个名为eventArgument参数,这是怎么实现参数的传递的呢?我们将在后面的章节进行讨论,现在在页面中添加如下的JavaScript函数代码
function CallServer(inputcontrol,context) { //回调还没有处理完全时其预先加载的显示值 context.innerHTML = "加载中......"; //为你在文本框中输入的信息,并且arg在这里就是将其值传递到 //RaiseCallbackEvent(String eventArgument)方法对应的eventArgument中 arg = inputcontrol.value; //获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。 <%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>; } |
参数 | 作用 |
control | 处理客户端回调的服务器 Control。该控件必须实现 ICallbackEventHandler 接口并提供 RaiseCallbackEvent 方法。 |
argument | 从客户端脚本传递一个参数到服务器端的RaiseCallbackEvent 方法。 |
clientCallback | 一个客户端事件处理程序的名称,该处理程序接收服务器端事件返回的结果。 |
context | 启动回调之前在客户端的客户端脚本信息。脚本的结果传回给客户端事件处理程序。 |
返回值 | 调用客户端回调的客户端函数的名称。 |
名称 | 说明 |
ClientScriptManager.GetCallbackEventReference (Control, String, String, String) | 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本和上下文。 |
ClientScriptManager.GetCallbackEventReference (Control, String, String, String, Boolean) | 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文和布尔值。 |
ClientScriptManager.GetCallbackEventReference (Control, String, String, String, String, Boolean) | 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文、错误处理程序和布尔值。 |
ClientScriptManager.GetCallbackEventReference (String, String, String, String, String, Boolean) | 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的目标、参数、客户端脚本、上下文、错误处理程序和布尔值。 我们就整个程序作个系统的说明,并且列出前台的页面代码和后台的逻辑代码,这样可以使得你对程序有个直观的理解。 |
|
读取数据库信息的客户端回调程序
本程序是一个实现读取Northwind数据库的Emlpoyees信息,为此你必须先保证Northwind数据库存在。下图是Emlpoyees表的内容。
这是查找到用户的显示结果 |
用户不存在的显示信息 |
01 using System; 02 using System.Data; 03 using System.Configuration; 04 using System.Collections; 05 using System.Web; 06 using System.Web.Security; 07 using System.Web.UI; 08 using System.Web.UI.WebControls; 09 using System.Web.UI.WebControls.WebParts; 10 using System.Web.UI.HtmlControls; 11 using System.Data.SqlClient; 12 public partial class ClientCallbacksSimple : System.Web.UI.Page, 13 13 System.Web.UI.ICallbackEventHandler 14 { 15 protected string strUserInfo; //保存读取的用户信息 16 //引发回调事件 17 public void RaiseCallbackEvent(string txtFirstName) 18 { 19 if (txtFirstName != null) 20 { 21 SqlConnection conn = new SqlConnection("data source=localhost;initial 22 catalog=Northwind;integrated security=SSPI"); 23 conn.Open(); 24 SqlCommand cmd = new SqlCommand("select EmployeeID,FirstName,City,Address 25 25 from Employees where FirstName=@FirstName", conn); 26 cmd.Parameters.Add("@FirstName", SqlDbType.NVarChar, 10).Value = txtFirstName; 27 SqlDataReader dr = cmd.ExecuteReader(); 28 if (dr.Read()) 29 { 30 strUserInfo = "员工代号:" + dr["EmployeeID"] + "\r\n"; 31 strUserInfo += "姓名:" + dr["FirstName"] + "\r\n"; 32 strUserInfo += "居住城市:" + dr["City"] + "\r\n"; 33 strUserInfo += "地址:" + dr["Address"].ToString().Replace("\r\n","")+ "\r\n"; 34 strUserInfo += "服务器查询时间:" + DateTime.Now.ToLongTimeString(); 35 } 36 else 37 { 38 if (String.IsNullOrEmpty(txtFirstName)) 39 { 40 strUserInfo = "请输入姓名"; 41 } 42 else 43 { 44 strUserInfo = "查无此人"; 45 } 46 } 47 cmd.Dispose(); 48 dr.Dispose(); 49 conn.Dispose(); 50 } 51 } 52 //回传回调结果 53 public string GetCallbackResult() 54 { 55 return strUserInfo; //回传员工的基本信息 56 } 57 } |
01 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ClientCallbacksSimple.aspx.cs" 02 Inherits="ClientCallbacksSimple" %> 03 <html xmlns="http://www.w3.org/1999/xhtml" > 04 <head runat="server"> 05 <title>读取数据库信息的客户端回调程序</title> 06 <script type="text/JavaScript"> 07 function OnCallback(strUserInfo,context) 08 { 09 Results.innerText = strUserInfo; 10 } 11 </script> 12 </head> 13 <body> 14 <form id="form1" runat="server"> 15 <div> 16 姓名:<input id="txtUserName" type="text" /> 17 <input id="btnCallback" type="button" value="回调" onclick="<%= 18 ClientScript.GetCallbackEventReference(this,"document.form1.txtUserName.value", 19 "OnCallback",null) %>" /> 20 <br /> 21 <div ID="Results" style="background-color: pink"></div> 22 </div> 23 </form> 24 </body> 25 </html> |