在ASP.NET 2.0 中使用无刷新功能[原创]

B/S结构与C/S结构在用户体验方面的诸多不同点当中,也许提交数据更改后的等待是B/S结构用户最不能忍受的,如果网速较慢,每次提交更改后都要等待一段时间,但是没有办法。于是实现无刷新的页面对Web应用程序来说就不仅仅是锦上添花,而是很有必要的了。在ASP.NET 2.0之前,人们想尽各种方法实现无刷新页面,不过自己实现起来很烦琐,也容易出错。ASP.NET 2.0出现之后,终于将无刷新功能集成到了它的类库里面,虽然它也是使用XMLHTML实现页面与服务器的交互,使用DHTML改变页面内容,与以前的作法没有太大的不同,但是它的封装使得更多的初级用户可以很方便的使用而不必关心它后台的实现。

在ASP.NET 2.0  当中,如果某个控件(或页面)要获得无刷新功能,只要实现ICallbackEventHandler接口。
这个接口要求实现一个方法

public string RaiseCallbackEvent(string eventArgument)

这个方法接收一个由页面传过来的string,在服务器端进行处理,然后返回一个string给页面由页面显示或处理。

那么这个方法是由哪里触发的呢?显然这个工作应该由页面上的javascript函数来做。我们只需要调用

ClientScriptManager.GetCallbackEventReference (Control, String, String, String)
在页面中可以通过Page.ClientScript.GetCallbackEventReference()调用;这个方法有4个重载,最简单的有
Control control,
string argument,
string clientCallback,
string context
四个参数。

分别表示:
1.需要处理返回值的控件,就是实现了ICallbackEventHandler接口的那个,因为页面上可能有几个不同的控件都实现了ICallbackEventHandler接口;
2.需要传回服务器的字符串值;
3.服务器端返回值后页面将要调用的函数名称,此函数应该有两个字符串型的参数;
4.另一个字符串型的参数,将会返回给页面中的处理函数(就是上一个参数所指明的那一个)。

Page.ClientScript.GetCallbackEventReference()函数返回一个字符串,是一个javascript 函数调用,类似于"WebForm_DoCallback('__Page',arg,ClientCallback,context,null,false)"。WebForm_DoCallback就是与服务器进行交互的那个函数了。里面的六个参数前四个由我们刚才提到的四个参数得到。第五个参数代表错误处理函数,第六个说明是否采用异步调用。

我们在页面中可以调用这个函数,给它传入正确的值,就可以获得服务器的结果,然后就会调用clientCallBack指定的函数改变页面内容。

由上面的讨论我们可以得出结论:要想让无刷新页面工作起来,页面中至少需要两个javascript函数,一个是用来调用WebForm_DoCallback这个函数的,另一个是由服务器调用用来改变页面内容的(就是那个clientCallBack)。不过不用担心,即使你对于javascritp不够熟悉,参考下面的例子这两个函数也很容易写。

例子(改写自ASP.NET Quickstart Tutorials中的一个例子):

 1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
 2
 3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 4<html xmlns="http://www.w3.org/1999/xhtml">
 5<head id="Head1" runat="server">
 6    <title>Client CallBack</title>
 7
 8    <script language="javascript">
 9    
10        function ClientCallback(result, context)
11        {
12            if (context == 'parent')
13            {
14                var childDropDown = document.forms[0].elements['<%=ChildDropDown.UniqueID%>'];
15
16                childDropDown.length = 0;
17                    
18                var rows = result.split('|'); 
19                for (var i = 0; i < rows.length; ++i){
20                    var option = document.createElement("OPTION");
21                    option.value = rows[i];
22                    option.innerHTML = rows[i];     
23                    childDropDown.appendChild(option);
24                }

25                    
26                childDropDown.style.visibility = "visible";
27            }

28            else if (context == 'child')
29            {
30                var label = document.all['<%=Label1.UniqueID%>'];
31                if (!label)
32                {
33                    return;
34                }

35                
36                label.innerHTML = result;
37            }

38        }

39
40    
</script>
41
42</head>
43<body>
44    <form id="Form1" runat="server">
45        <h3>
46            无刷新DropDownList</h3>
47        <asp:DropDownList ID="ParentDropDown" onchange="GetChildren(this.options[this.selectedIndex].value, 'parent');"
48            runat="server">
49            <asp:ListItem Text="1" />
50            <asp:ListItem Text="2" />
51            <asp:ListItem Text="3" />
52        </asp:DropDownList>
53        <asp:DropDownList ID="ChildDropDown" runat="Server" onchange="GetChildren('GetResult:' + ParentDropDown.options[ParentDropDown.selectedIndex].value + ':' + this.options[this.selectedIndex].value, 'child')"
54            Style="visibility: hidden">
55        </asp:DropDownList>
56        <br />
57        <br />
58        <asp:Label ID="Label1" runat="server" />
59    </form>
60</body>
61</html>
62


后台代码: 

 1using System;
 2using System.Web.UI;
 3using System.Collections.Generic;
 4
 5public partial class _Default : System.Web.UI.Page, ICallbackEventHandler
 6{
 7    private void Page_Load(object source, EventArgs e)
 8    {
 9        String callBack = Page.ClientScript.GetCallbackEventReference(this"arg""'ClientCallback'""context");
10        String clientFunction = "function GetChildren(arg, context){ " + callBack + "; }";
11        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "GetChildren", clientFunction, true);
12
13    }

14
15    public string RaiseCallbackEvent(string eventArgument)
16    {
17        if (eventArgument.Contains("GetResult"))
18        {
19            string[] strings = eventArgument.Split(new char[] ':' });
20            return "你选择了: " + strings[1+ "" + strings[2];
21        }

22        else
23        {
24            switch (eventArgument)
25            {
26                case "1":
27                    return "A|B|C";
28                case "2":
29                    return "D|E|F";
30                case "3":
31                    return "G|H|I";
32                default:
33                    return "";
34            }

35        }

36    }

37}

38

在上面的例子中,页面中只有两个javascript函数:ClientCallback和GetChildren
注意到GetChildren有两个参数arg和context。
ClientCallback也有两个参数result和context。
前面提到服务器端的RaiseCallbackEvent方法,在这个例子中GetChildren中的参数arg传给RaiseCallbackEvent,RaiseCallbackEvent的返回值传给ClientCallback的参数result。GetChildren的参数context则无变化的传给ClientCallback的参数context。
也就是说,GetChildren搜集页面中的数据传回服务器,ClientCallback接收服务器的数据显示到页面。

这之间的纽带就是WebForm_DoCallback这个函数,这个函数实现在哪里呢?查看源文件可以看到页面中有类似于
<script src="/DropDownListDemo/WebResource.axd?d=jK3gw2MPRKrLc7QZ4EMGSA2&amp;t=632506260630156250" type="text/javascript"></script>

的这么一行。就是ASP.NET用来实现无刷新的javascript脚本文件。当然,直接看是不容易看到的。这时可以取个巧,制造一个错误,然后利用调试器来查看。具体做法是这样的,你可以把代码中的这一行
        String callBack = Page.ClientScript.GetCallbackEventReference(this, "arg", "ClientCallback", "context");
改成
        String callBack = Page.ClientScript.GetCallbackEventReference(this, "arg", "'ClientCallback'", "context");
这样就可以出现运行时错误,然后就可以选用Microsoft Script Editor调试器进行调试,就可以看到这里面的代码了。不过注意,要开启客户端脚本调试,需要在Internet 选项的“高级”里取消选定“禁用脚本调试”。

posted on 2005-05-05 16:31  Chiewen Ly  阅读(1456)  评论(1)    收藏  举报