架构深渊

慢慢走进程序的深渊……关注领域驱动设计、测试驱动开发、设计模式、企业应用架构模式……积累技术细节,以设计架构为宗。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

我的局部刷新

Posted on 2008-11-20 20:59  chen eric  阅读(287)  评论(0编辑  收藏  举报
 

    使用过.net中的局部刷新功能兄弟都知道,据我的认识,最用的是微软自己提供的和第三方提供组件.微软的提供的方法有两种,一种是VS2005提供的UpdatePanel组件,把updatepanel拖进页面,然后要进行局部刷新的内容(如gridview),只要在updatepanel这个容器里的控件都可以做到局部刷新;第二种方法是VS2003中就有的,即让页面的后代码类实现ICallbackEventHandler接口,该接口有两个方法,RaiseCallbackEvent方法用于客户端处理传过来请求,其中参数是客户端传过来的(JS),GetCallbackResult(没有参数)用于服务器端返回给客户端的结果(text或XML),另外在Page_Load还必须向客户端注册向调用服务器端的脚本,客户端调用这个脚本中函数得到响应数据,具体的细节在这里就多讲了.第三方组件,我知道Ajaxpro,偶没用过.另外,不管是微软提供的还是第三方的方法,我注意到,在运行时向页面注册一些资源文件(js),即一些函数.当然单独注册在页面的也有.
   在使用微软的方法实现局部刷新时,我发现一个问题,如果一个页面加载的数据量(2000条记录)很大时,我要刷新的局部数据量很少,只有数据库中的一条记录.异步刷新的速度很慢,和页面加载的数据量成正比,即页面数据量越大,本身整个页面加载的时间就越慢,而局部刷新也会越慢.这不是我们要的局部刷新吧.
   
仔细看了ajax组件生成的资源文件,仔细看了下代码,大概地了解了,当页面做异步请求时(通过XMLHttpRequest对象),它把请求对象指向了本身即,请求的url是页面中Form的action的值,而Post对参数呢,应该是form里所有的表单字段,所以post的数据量就该不会少,另外,在服务器执行的时候,页面要模拟正常情况执行一遍(这里包括PageLoad方法),然后把再响应的数据丢给XMLHttpRequest,我有一点不明白的是,微软的这种异步请求,是把部分数据还是所有数据丢给XMLHttpRequest对象呢,还有就是在客户端怎么处理返回的数据.
    
我有一点可以肯定的,页面把正常时操作的流程全走了一遍,如果页面数据量大的话,则会把这些数据再读一遍.而这也许是我们所不需要的.
    讲了这么多,看看我的方法,有点老土,用原始的ajax操作来完成.
    基本的原理:在客户端,建立XMLHttpRequest对象,请求的对象也是页面本身.传的参数是请求用到的参数,应该很少吧,其中包括一个ajax请求的标识符;建立两个函数于,用于执行请求成功和失败后的操作.在服务器端,需要在两个地方进行操作,一个是Page_Load方法,一个是页面被重写了的OnPreRender方法.前者是在判断有ajax请求的参数时,立即返回,不执行pageload包括的其它代码,OnPreRender用于输出,即返回给XMLHttpRequest的字符串.
   具体我将用代码做解释,如下:
   客户端用到的代码:
   1.Ajax请求函数:


 1//建XMLHttpRequest对象,适应于firefox,ie
 2    if(typeof XMLHttpRequest=="undefined" && window.ActiveXObject)
 3        {
 4            function XMLHttpRequest()
 5            {
 6                var arrSign=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
 7                for (var i=0;i<arrSign.length;i++)
 8                {
 9                    try{
10                        var oRequest=new ActiveXObject(arrSign[i]);
11                        return oRequest;
12                    }

13                    catch(oError)
14                    {}
15                }

16                throw new Error("MSXML is not installed");
17            }

18        }

19        //Complete是请求时执行的函数,fail是失败时执行
20        function request(url,Param,Complete,fail,Method,isAsnc)
21        {            
22           var oRequest=new XMLHttpRequest(); 
23           if(!Method) Method="post";           
24           if(!isAsnc) isAsnc=false;
25           oRequest.open(Method,url,isAsnc);
26           oRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");           
27           oRequest.onreadystatechange=function()
28            {
29               if(oRequest.readyState==4)
30                {
31                   //alert(oRequest.ResponseText);
32                   if(oRequest.status==200)
33                   {
34                      
35                      if(typeof(Complete)=="function"
36                      {
37                       Complete(oRequest);                      
38                      }

39                    }

40                     else
41                        if(typeof(fail)=="function") fail(oRequest);
42                }
                   
43                
44            }
//
45            oRequest.send(Param); 
46        }

     2.以下是前台页面的用到函数.

 1 <script type="text/javascript" language=javascript src="js/include.js"></script>
 2    <script type="text/javascript" language=javascript>
 3        if(typeof($)!="function")
 4        {   
 5            function $(id)
 6           {
 7                    return document.getElementById(id); 
 8           }

 9        }

10        //fpDetail 是页面中一个div的id,页面中某个地方将调用cc()这个方法
11        function cc(para)
12        {
13            var pars="callback=1&para="+para;
14             request($("<%=form1.ClientID%>").action,pars,showResponse,showAlert,null,true);
15            return false;
16        }

17        function showResponse(originalRequest)
18        {     
19            $("fpDetail").innerHTML=originalRequest.responseText;        
20        }

21    function showAlert(request)
22    {
23        alert("Some Error appear!\r\n"+request.statusText);
24    }

25    </script>

          3.后代码文件,主要包括page_load里的操作和OnPreRender里的操作.

 1 protected void Page_Load(object sender, EventArgs e)
 2    {
 3        string callBack;
 4        callBack = Request.Form["callback"];
 5        if (callBack != null && callBack == "1")
 6        {
 7            return;
 8        }

 9        Button1.Attributes.Add("onclick""return cc();");
10       .
11       .
12       .
13       .
14       .//其它操作
15    }


 1protected override void OnPreRender(EventArgs e)
 2    {
 3        //gv1是一个GridView对象
 4        string callBack;
 5        callBack=Request.Form["callback"];
 6        if (callBack != null && callBack == "1")
 7        {
 8            Response.Clear();
 9            //GYF.ExecuteQuery返回一个Datatable
10            gv1.DataSource = GYF.ExecuteQuery("sql语句");
11            gv1.DataBind();
12            StringBuilder sb = new StringBuilder();
13            gv1.RenderControl(new HtmlTextWriter(new StringWriter(sb)));            
14            Response.Write(sb.ToString());
15            Response.End();
16        }

17        else
18            base.OnPreRender(e);
19    }

       最后,需要注意的是,.net在ajax请求时会验证服务器端控件,如Gridview导出excel时,ajax这种请求可能使得一些服务器控件没有在前端呈现,以致于通不过页面验证,这里可以做如下修正:
      1.前端页面中<%page%>中加入 EnableEventValidation=False;
      2.重写页面的方法VerifyRenderingInServerForm方法
         public override void VerifyRenderingInServerForm(Control control)
         {
             //什么都不做.
        }

       好了,总算完了,写了好久啊.
      希望大家发表下看法.