ASP.NET AJAX(3)__UpdatePanel

时间:2022-05-03
本文章向大家介绍ASP.NET AJAX(3)__UpdatePanel,主要内容包括UpdatePanel的一些属性、相关的API、相关控件、ASP.NET 2.0脚本注册、错误处理、PageRequestManager类、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

今天也不知道写不写的完了,最近闲下来了,却感冒了,早上起来都不会说话了,不过幸亏咱不是靠嘴皮子过活了,哎~~~~窃喜吧

上一篇简单写到UpdatePanel的一些好处和坏处,这一篇呢,就细致的认识一下UpdatePanel这个控件,并合理的使用它

UpdatePanel的一些属性

RenderMode     __Block(默认值):设定UpdatePanel使用DIV来圈出要跟新的区域     __Inline:设定UpdatePanel使用span来。。。。。。 UpdateMode     __Always(默认值):在完成一次异步回送以后,总是更新     __Conditional:。。。。。以后,有条件的更新,在平时使用时候,一定要使必要的UpdatePanel更新,这样才可以减 少服务器端以及带宽的压力 ChildrenAsTrigger(具体设置下面将会看到)     __True(默认):     __False: Triggers 集合属性     __AsyncPostBackTrigger:指定异步回送的触发器     __PostBackTrigger:指定同步回送的触发器

看一个UpdatePanel的示例

首先在页面中加入一个ScriptManager,这个控件起一个对AJAX的一个统一管理调配的作用,一个页面中有且仅有一个,我们通常会把它放到母板页里,方便使用 页面代码 我放这里:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RenderMode.aspx.cs" Inherits="Demo02_RenderMode" %>

<!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></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" RenderMode="Block">
            <ContentTemplate>
                RenderMode="Block"
            </ContentTemplate>
        </asp:UpdatePanel>
        Xiaoyaojian
        <hr />
        
        <asp:UpdatePanel ID="UpdatePanel2" runat="server" RenderMode="Inline">
            <ContentTemplate>
                RenderMode="Inline" 
            </ContentTemplate>
        </asp:UpdatePanel>
        Xiaoyaojian
    </form>
</body>
</html>

显示结果是:

很明显 在 RenderMode="Block" 的时候,UpdatePanel是独占一行的,而RenderMode="Inline" 的时候则不是在生成的代码中,我们也可以看到

<div id="UpdatePanel1">
    
                RenderMode="Block"
            
</div>
        Xiaoyaojian
        <hr />
        
        <span id="UpdatePanel2">
                RenderMode="Inline"
            </span>
        Xiaoyaojian

这里再做一个属性ChildrenAsTrigger的示例,因为我觉得其他的也没必要,一看就基本可以明白的 页面代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <%= DateTime.Now %>
            </ContentTemplate>
        </asp:UpdatePanel>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server" ChildrenAsTriggers="false" UpdateMode="Conditional">
            <ContentTemplate>
                <%= DateTime.Now %>
                <asp:Button ID="Button1" runat="server" Text="Button" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>

这样的话,我们点击Button1的话,只有上面的时间会更新,而下面的不会,而如果我们去除ChildrenAsTriggers="false"的话,上下两个时间就都会更新,这是为什么呢?因为在上面一个UpdatePanel中,他的UpdateMode为Always,所以在点击按钮时候,它总会更新,但是下面一个UpdatePanel中,ChildrenAsTriggers="false" UpdateMode="Conditional",所以它不会更新,那么怎么让下面这个UpdatePanel也更新呢,在异步回送的前提下,就只有一种方法,就是添加Trigger,指定一个AsyncPostBackTrigger的ControlID为某一个控件的ID,或者有需要的话 还可以指定它的Event,代码如下

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <%= DateTime.Now %>
            </ContentTemplate>
        </asp:UpdatePanel>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server" ChildrenAsTriggers="false" UpdateMode="Conditional">
            <ContentTemplate>
                <%= DateTime.Now %>
                <asp:Button ID="Button1" runat="server" Text="Button" />
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Button2" />
            </Triggers>
        </asp:UpdatePanel>
    <asp:Button ID="Button2" runat="server" Text="Button" />
    </form>
</body>
</html>

这样,点击Button2,两个时间就都可以更新了

相关的API

UpdaPanel     __Update方法:使用UpdatePanel更新     __IsInPartialRendering属性:判断UpdatePanel是否在输出过程中(在UpdatePanel的Render(生成代码)时候)

ScriptManager     __GetCurrent静态方法:或者当前页面上的ScriptManager对象    __IsInAsyncPostBack:是否在异步回送过程中    __RegisterAsyncPostBackControl方法:指定控件为一个异步回送控件    __RegisterPostBackControl方法:指定控件为传统回送控件

写一个实例

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                <%= DateTime.Now %>
            </ContentTemplate>
        </asp:UpdatePanel>
        
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </form>
</body>
</html>

这时点击Button,UpdatePanel是不更新的,如果想让时间异步更新,我们可以在页面的Page_Load事件处理程序中加入

ScriptManager.GetCurrent(this.Page).RegisterAsyncPostBackControl(this.Button1);

这样点击Button,页面已经不是传统的回送了,这就是RegisterAsyncPostBackControl起的作用,但是时间还是没有变化,说明UpdatePanel没有更新,我们再在Button的Click事件处理程序中,加入

this.UpdatePanel1.Update();

这时再点击按钮,时间更新,因为我们强制了UpdatePanel1的更新

其实呢,这里更直观的一种做法是把Button1设置到UpdatePanel1的AsyncPostBackTriggers中

然后,我们再在UpdatePanel中加入一个按钮,点击这个按钮,会产生一个异步的回送,引起UpdatePanel1的更新,如果我们想让这个按钮引发一个传统的回送,就可以在Page_Load事件处理程序中加入一下代码

ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(this.Button2);

这时,我们再点击Button2时候,引发的就是一个传统的回送,这个我们可以通过滚动条或者前进后退按钮,证明它是一个传统的回送

这时,如果我们再在UpdatePanel1里注册一个AsyncPostBackTrigger为Button2,就会出现一个应用程序错误,原因显而易见

相关控件

UpdateProgress

    当网页包含一个或多个用于部分页呈现的 UpdatePanel 控件时,UpdateProgress 控件可帮助您设计更为直观的 UI。如果部分页更新速度较慢,则可以使用 UpdateProgress 控件来提供有关更新状态的可视反馈。可以在页上放置多个 UpdateProgress 控件,其中每个控件都与不同的 UpdatePanel 控件相关联。也可以使用一个 UpdateProgress 控件,并将其与页上的所有 UpdatePanel 控件关联,常用的情况呢,就是在类似网速比较慢,或者请求数据量大或者会拖延较长时间的时候,使用UpdateProgress和用户进行交互,让用户知道页面在更新,而不是一种假死或者其他的状态

UpdateProgress的几个属性

DynameicLayout(默认True):通常情况下是否占位 DisplayAfter(默认500):在UpdatePanel发起更新后多长时间显示 AssociatedUpdatePanelID:指定要关联的UpdatePanel

Timer

Timer 控件是一个服务器控件,它会将一个 JavaScript 组件嵌入到网页中。当经过 Interval 属性中定义的时间间隔时,该 JavaScript 组件将从浏览器启动回发。您可以在运行于服务器上的代码中设置 Timer 控件的属性,这些属性将传递到该 JavaScript 组件。

若回发是由 Timer 控件启动的,则 Timer 控件将在服务器上引发 Tick 事件。当页发送到服务器时,可以创建 Tick 事件的事件处理程序来执行一些操作。

设置 Interval 属性可指定回发发生的频率,而设置 Enabled 属性可打开或关闭 Timer。Interval 属性是以毫秒为单位定义的,其默认值为 60,000 毫秒(即 60 秒)。

这里需要注意一点:

将 Timer 控件的 Interval 属性设置为一个较小值会产生发送到 Web 服务器的大量通信,对服务器的压力会明显提升。使用 Timer 控件可以仅按所需的频率刷新内容

一个UpdateProgress示例

在页面中添加如下代码:

<form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <%= DateTime.Now %><br />
                <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>

然后在Button1的Click事件处理程序中,写入

System.Threading.Thread.Sleep(3000);

这样就可以让服务器端在按钮点击后等待三秒后再发回数据,这样,我们在点击按钮3秒之内,页面就会假死在那里,所以我们需要在这三秒内给用户一个提示

所以,我们在UpdatePanel上方添加如下代码

<asp:UpdateProgress ID="UpdateProgress1" runat="server" DynamicLayout="false" DisplayAfter="500">
            <ProgressTemplate>
                加载中...
            </ProgressTemplate>
        </asp:UpdateProgress>

这时,在页面中UpdatePanel上方的位置就出现了一块空白,这就是DynamicLayout="false"的效果,如果设置为True,则不会出现这块空白

当我们点击Button1后半秒(DisplayAfter="500")后,UpdatePanel上方出现“加载中…”字样,UpdatePanel更新完毕后,字样消失,这就是UpdateProgress给出的提示

注意:如果这里我们在UpdatePanel中加入AsyncPostBackTrigger指定一个UpdatePanel外部的控件作为UpdatePanel更新的触发器,并且在UpdateProgress中设置了AssociatedUpdatePanelID="UpdatePanel1",则外部设置的控件的相应事件的触发,UpdateProgress不会起作用‘

ASP.NET 2.0脚本注册

比如我们需要在用户点击一个按钮时候,弹出一个提示框之类的东西,我们往往会通过Response.Writer然后输出一段javascript,这在通常情况下是可行的,但是我们看接下来的一个示例

页面代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
        
    <asp:Button ID="Button2" runat="server" Text="Button" onclick="Button2_Click" />
    </form>
</body>
</html>

在两个按钮的单击事件处理程序中,加入如下代码:

Response.Write("<script>alert('Xiaoyaojian');</script>");

这样,我们可以发现,在单击UpdatePanel外的一个按钮时,程序正常弹出一个提示框,但是当我们点击UpdatePanel内的一个按钮的时候,页面不能弹出提示框,并且会出现一个错误,这是一个典型的问题,其实使用这种方式给客户端写入脚本代码是一个非常拙劣的做法,接下来我们看一些ASP.NET 2.0提供的一些标准的操作脚本的方法

一个示例

创建一个页面,在页面中添加一个服务端按钮,在按钮的单击事件处理程序中,加入一下代码:

 ClientScriptManager csm = this.ClientScript;

        csm.RegisterArrayDeclaration("hello", "1,2,3");//常见一个名为hello的数组,内容为1,2,3

        csm.RegisterClientScriptBlock(this.GetType(), "afunction", "function alertMessage(){alert('xiaoyaojian');}", true);//注册一个代码段
        csm.RegisterClientScriptInclude("jsDocScript", "jsDoc.js");//引入一个名为jsDoc.js的文件,jsDocScript作为它的key,防止重复载入
        csm.RegisterExpandoAttribute(this.Button1.ClientID, "xiaobai", "xiaoyaojian");//为Button1添加一个名为xiaobai的属性,值为xiaoyaojian 注意一定要是控件的ClientID,因为服务器端控件发送到客户端后,它的ID是经过一定的规则转变过的 
        csm.RegisterHiddenField("xiaobai", "xiaoyaojian");//在页面中添加一个隐藏域
        csm.RegisterOnSubmitStatement(this.GetType(), "xiaoyaojian", "return window.confirm('Are you sure to delete?')");//可以添加一段语句,如果返回true,则此次提交可以成功,如果返回false,则提交不会成功
        csm.RegisterStartupScript(this.GetType(), "xiaoyaojian", "<script>alert('xiaoyaojian');</script>");

打开网页,我们可以在页面源代码中找下如下内容(与上面的语句一一对应):

1.

<script type="text/javascript"> 
//<![CDATA[
var hello =  new Array(1,2,3);
//]]>
</script>
2.
<script type="text/javascript"> 
//<![CDATA[
function alertMessage(){alert('xiaoyaojian');}//]]>
</script>

3.
<script src="jsDoc.js" type="text/javascript"></script>
4.
<input type="hidden" name="xiaobai" id="xiaobai" value="xiaoyaojian" />

5.
<script type="text/javascript"> 
//<![CDATA[
function WebForm_OnSubmit() {
return window.confirm('Are you sure to delete?');
return true;
}
//]]>
</script>
6.
<script>alert('xiaoyaojian');</script></form>

这里需要讲一下第五句和第六句的区别,他们两个方法注册脚本的区别就在,RegisterOnSubmitStatement将脚本注册在了显示内容的最上边,而RegisterStartupScript则刚好相反

那么,在异步更新状态中注册脚本,则是使用ScriptManager对应的那几个静态方法

新方法和旧方法的区别    ___方法都会多接受一个参数    ___并非所有注册脚本都会生效:只有在注册的控件更新后,注册的脚本才会生效(如果想让这个脚本一定会生效,我们就可以把第一个参数该为当前Page)    ___RegisterExpandoAttribute方法多一个encode参数

一个异步更新状态下注册脚本的示例

常见一个页面

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <%= DateTime.Now %><br />
                <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>

在按钮的单击事件处理程序中加入如下代码:

ScriptManager.RegisterStartupScript(this.UpdatePanel1, this.GetType(), "key_1", "alert('xiaoyaojian');", true);

第一个参数,是一个Control类型的参数(重载为Page类型),表示为哪个控件注册脚本,这就是多出来的那个参数,最后一个参数,表示是不是为注册的脚本加入一个<script>标记

这时我们在点击按钮,就可以正常弹出提示框了,这就解决了我们一开始遗留的那个问题

错误处理

服务器ScriptManager相应设置

   ___AllowCustomErrorsRedirect属性:遇到错误时,是否根据web.config中的设置进行跳转,默认设置为True

   ___AsyncPostBackError事件:异步刷新中遇到错误时,此事件被触发

   ___AsyncPostBackErrorMessage属性:客户端接受到的错误信息

在我们自行处理错误的时候,就需要在客户端响应PageRequestManager中的endRequest事件,并将errorHandled属性设置为True

一个关于错误处理的示例

现在如果使用Visual Studio 2008中创建网站,默认的customErrors结点是被注释掉的,我们对这个节点做如下操作

1.首先将注释取消,然后设置mode="On",defaultRedirect设置为我们要跳转到的错误页面,这里我们让他跳转到我们将要创建的Error.aspx,

2,创建这个Error.aspx,里面添加一些自定义的错误提示

3.创建一个要发生错误的页面

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>

在按钮点击事件中抛出一个异常,然后浏览页面,点击按钮,就会自动跳转到我们设定的默认错误页面

那么,如果想在当前出现错误的页面中处理错误,就要这样做

首先把AllowCustomErrorsRedirect="false"

然后在页面中添加如下代码

<div id="error"></div>
        <script type="text/javascript" language="javascript">
            Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(sender, e) {
                e.set_errorHandled(true);//表示我们已经处理了这个错误
                $get("error").innerHTML = "出现一个错误";
            });
        </script>

一个动态创建UpdatePanel的示例:

  1. 创建一个页面
  2. 在页面的Load事件中加入如下代码

UpdatePanel updatePanel = new UpdatePanel(); updatePanel.ID = "up1"; this.Form.Controls.Add(updatePanel);//这是服务端控件的要求,必须添加到Form中 LiteralControl literalControl = new LiteralControl(DateTime.Now.ToString()); updatePanel.ContentTemplateContainer.Controls.Add(literalControl);//这里是添加到ContentTemplateContainer,而不是ContentTemplate Button button = new Button(); button.Text = "按钮"; updatePanel.ContentTemplateContainer.Controls.Add(button);

PageRequestManager类

  •           getInstance静态方法:获得全局唯一的PageRequestManager实例
  •           isInAsyncPostBack属性:是否出于异步更新过程中
  •           abortPostBack方法:取消当前异步更新,多次调用不会产生异常

     PageRequestManager在客户端形成的声明周期(异步刷新时触发)

  • initializeRequest
  • beginRequest
  • pageLoading
  • pageLoaded
  • endRequest

      PageRequestManager__initializeRequest事件

  • request属性: 用于获得WebRequest对象(用于请求的信息)
  • postBackElement:出发异步刷新的DOM元素

          常用的操作

  • 读取请求信息
  • 取消此次异步更新

        一个示例

            如果我们要在一个优先级高的异步回送发起时,取消已经发起的优先级较低的操作,而在一个优先级较低的异步回送发起时,如果一优先级高的异步回送还没有完成时,而阻止此次异步回送时,我们就可以在PageRequestManager的initializeRequest中做如下操作

<script language="javascript" type="text/javascript">
        var lastPostBackButtonId = null;
        var btnPrecedenceId = "<%= this.btnPrecedence.ClientID %>";//优先级高的按钮的客户端ID

        Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(
            function(sender, e) {
                var prm = Sys.WebForms.PageRequestManager.getInstance();
                if (prm.get_isInAsyncPostBack()) {//判断是否在异步会动过程中
                    if (lastPostBackButtonId == btnPrecedenceId) {
                        e.set_cancel(true); //取消操作
                        //e.get_postBackElement().id 得到发起回送的元素ID
                        if (e.get_postBackElement().id == btnPrecedenceId) {
                            showMessage("不可重复发起优先的刷新。");
                        }
                        else {
                            showMessage("请等待优先的刷新结束。");
                        }
                    }
                    else {
                        if (e.get_postBackElement().id == btnPrecedenceId) {
                            showMessage("发起优先的刷新,普通的刷新讲被取消");
                        }
                        else {
                            showMessage("重新发起普通的刷新,前一次提交将要被取消");
                        }
                    }
                    lastPostBackButtonId = e.get_postBackElement().id;
                }
            }
        );
    </script>

PageRequestManager__begingRequest事件

  • request属性
  • postBackElement

      常用的操作:

  • 读取请求信息
  • 改变请求方式(替换Executor)
  • 显示更新提示

一个强制显示UpdateProgress的示例

创建一个页面,添加ScriptManager并添加如下代码

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <%= DateTime.Now %>
            <br />
            <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button_Click" />
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button2" />
        </Triggers>
    </asp:UpdatePanel>
    <asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="1000" AssociatedUpdatePanelID="UpdatePanel1">
        <ProgressTemplate>
            <span style="color:Red">Loading...</span>
        </ProgressTemplate>
    </asp:UpdateProgress>
    <hr />
    <asp:Button ID="Button2" runat="server" Text="Button"  OnClick="Button_Click"/>

并在按钮的点击事件中,让他线程停止两秒种,这样我们会发现,在点击UpdatePanel外的一个按钮的时候,UpdateProgress并没有显示Loading字样,其实这就是在UpdateProgress绑定一个UpdatePanel后产生的一个问题,只有UpdatePanel内的控件触发的异步回送,UpdateProgress才会做出反映

我们要让这个UpdateProgress对外部控件引发的异步回送产生反映,就可以模仿UpdateProgress内的一个startRequest方法

在页面上我们嵌入如下代码

<script language="javascript" type="text/javascript">
        Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(
        function(sender, e) {
            if (e.get_postBackElement().id != "<%=this.Button2.ClientID %>") {
                return;
            }
            var updateProgress = $get("<%= this.UpdateProgress1.ClientID %>");
            var dynamicLayout =<%=this.UpdateProgress1.DynamicLayout.ToString().ToLower() %>;
            if(dynamicLayout)
            {
                updateProgress.style.display="block";
            }
            else
            {
                updateProgress.style.visibility="visible";
            }

        });
    </script>

这样,我们就实现了强制UpdateProgress的显示

PageRequestManager__pageLoading事件

  • dateItems属性:获得服务器端注册的数据项
  • panelsDeleting属性:获得即将删除的UpdatePanel
  • panelsUpdating属性:获得即将更新的UpdatePanel

    常用操作

  • 提示更新的UpdatePanel
  • 获得服务器注册的数据项

        一个提示更新的UpdatePanel的示例

首先,我们创建一个用户控件,里面仅仅包含一个UpdatePanel用来显示当前事件,它的UpdateMode="Conditional",然后在它codefile中,加入如下代码

 private static Random random = new Random(DateTime.Now.Millisecond);
    protected void Page_Load(object sender, EventArgs e)
    {
        
        if (random.NextDouble() > 0.5)
        {
            this.UpdatePanel1.Update();
        }
    }

这样,他每次只有一般的几率会更新

创建一个页面,添加若干个上面的用户控件,然后在页面Loadin事件里,注册一个异步更新的按钮

如果我们要高亮显示更新的UpdatePanel,就可以利用pageLoading这个事件,在页面中加入如下代码:

<script language="javascript" type="text/javascript">
        function highlightPanels(panels, clear) {
            for (var i = 0; i < panels.length; i++) {
                var panel = panels[i];
                panel.style.border = clear ? "solid 0px white" : "solid 2px red";
            }
        }
        Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(
        function(sender, e) {
        var panelUpdating = Array.clone(e.get_panelsUpdating());//得到要更新的UpdatePanel
            highlightPanels(panelUpdating,false);
            window.setTimeout(function() { highlightPanels(panelUpdating,true)},2000);
        }
        );
    </script>

这样,就可以提示用户哪个UpdatePanel将会被更新了,这就是一个典型利用pageLoading事件的例子

PageRequestManager___pageLoaded事件

  • dateItems属性:获得服务端注册的数据项
  • panelsCreated属性:获得新建的UpdatePanel
  • panelsUpdated属性:获得已经更新的UpdatePanel

       常用操作

  • 获得服务器端注册的数据项
  • 执行服务器端注册的脚本

一个局部内容添加的示例

新建一个页面,添加ScriptManager,然后添加如下代码

<strong>Comment</strong><hr /><hr />
    
    <div id="commentContainer">
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Repeater ID="Repeater1" runat="server">
                    <ItemTemplate>
                        <%# (Container.DataItem as Comment).Content %><br />
                        <i><%#(Container.DataItem as Comment).Time %></i>
                        <hr />
                    </ItemTemplate>
                </asp:Repeater>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="Button1" />
            </Triggers>
        </asp:UpdatePanel>
        
    </div>
    <br />
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><hr />
    <asp:Button ID="Button1" runat="server" Text="Add Comment" 
        onclick="Button1_Click" />

然后,在页面的codefile里添加

private static List<Comment> Comments;


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!this.IsPostBack)
        {
            Comments = new List<Comment>();
            this.BindComments();

        }
    }

    private void BindComments()
    {
        this.Repeater1.DataSource = Comments;
        this.Repeater1.DataBind();
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Comment comment = new Comment();
        comment.Content = this.TextBox1.Text;
        comment.Time = DateTime.Now;
        Comments.Add(comment);
        //this.Repeater1.DataSource = new Comment[] { comment };
        this.BindComments();
        //this.Repeater1.DataBind();
    }

Comment类就是简单的两个公有字段Content和Time,这样我们就完成了一个类似论坛回帖的这么一个效果,但是,我们现在每次更新都是更新的整个UpdatePanel,随着这个回复的增加,服务器端需要处理并发回的数据量就会一点一点增加,所以我们要做一下的操作来减少这样的没有必要的数据量的传输

首先我们要知道,服务器端是怎么知道要更新的是哪个UpdatePanel的,它是通过UpdatePanel的ID来找到的,我们要做的就是让要寻找的不是当前要更新的ID

首先修改按钮点击事件的代码

 protected void Button1_Click(object sender, EventArgs e)
    {
        Comment comment = new Comment();
        comment.Content = this.TextBox1.Text;
        comment.Time = DateTime.Now;
        //Comments.Add(comment);
        this.Repeater1.DataSource = new Comment[] { comment };
        //this.BindComments();
        this.Repeater1.DataBind();
    }

然后在页面中,锲入如下的javascript代码

<script language="javascript" type="text/javascript">
        Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(
            function(sender, e) {
                var upId = "<%=this.UpdatePanel1.ClientID %>";//得到UpdatePanel的客户端ID
                var refreshedPanels = e.get_panelsUpdated();//得到所有已经更新的UpdatePanel
                for (var i = 0; i < refreshedPanels.length; i++) {//遍历所有已经更新的UpdatePanel
                    if (refreshedPanels[i].id == upId) {//如果发现我们需要的UpdatePanel已经更新
                        refreshedPanels[i].id = upId + Math.floor(9999 * Math.random());//首先改变原来的UpdatePanel的ID
                        var div = document.createElement("div");//创建一个DIV
                        div.id = upId;//把这个DIV的ID设置为要更新的UpdatePanel的ID
                        $get("commentContainer").appendChild(div);//然后把它添加到大的DIV的末尾
                        return;
                    }
                }
            }
        );
    </script>

这样我们新建了一个DIV,让传过来的新的数据放到这个DIV里,我们就完成了和一开始一样的功能,而且,我们现在用一些工具的查看的时候,每回发回的数据就不会逐渐的增加啦

PageRequestManager___endRequest事件

  • dateItems属性:获得服务器端注册的数据项
  • error属性:获得异步刷新时出现的错误
  • errorHandled属性:表明错误是否已经被处理
  • response属性:获得这次请求获得的结果对象

     常用操作

  • 处理异步刷新结果(异常,超时等)
  • 获得请求结果中额外的信息

一个处理异步刷新结果的示例

创建一个页面,添加ScriptManager,然后添加如下代码

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <%= DateTime.Now %><hr />
            <asp:Button ID="btnError" runat="server" Text="Error" 
                onclick="btnError_Click" />
            <asp:Button ID="btnTimeout" runat="server" Text="Timeout" 
                onclick="btnTimeout_Click" />
            <input id="Button2" type="button" value="Abort" onclick="Sys.WebForms.PageRequestManager.getInstance().abortPostBack();"/>
            <asp:Button ID="btnDataItem" runat="server" Text="Register DataItem" 
                onclick="btnDataItem_Click" />
        </ContentTemplate>      
    </asp:UpdatePanel>

在btnError的Click事件中,随便抛出一个异常,刷新页面,点击按钮,页面就会出现一个黄色叹号的警告,那么我们就要在客户端处理它,让它变得比较友好,或者说,可以让我们随意的处理

在页面中锲入如下脚本

<script language="javascript" type="text/javascript">
        Sys.WebForms.PageRequestManager.getInstance().add_endRequest(
        function(sender, e) {
        if (e.get_error()) {//如果遇到了错误
            e.set_errorHandled(true);//设置错误已被处理

            if (e.get_response().get_timedOut()) {//判断是否为超时错误
                showMessage("您的请求已超时。");
            }
            else if (e.get_response().get_statusCode() != 200) {//判断错误类型,状态码不是200的,统统定义为未知错误
                showMessage("遇到未知错误。");
            }
            else {
                showMessage(e.get_error().message);//输出错误信息
            }
        }
        else if (e.get_response().get_aborted()) {
            showMessage("您的请求已被取消。");
        }
        else {
            var upId = "<%= this.UpdatePanel1.ClientID %>";
            var item = e.get_dataItems()[upId];
            showMessage("您注册了:" + item);
        }
        }
        );
    </script>

这样,我们就可以判断错误类型,并给出相应的提示

在btnDataItem单击事件中,添加如下代码

ScriptManager.GetCurrent(this).RegisterDataItem(this.UpdatePanel1, DateTime.Now.ToString());

这样就可以得到注册的数据项了

如果要取消一个异步回送,就可以在客户端的按钮点击事件中,执行如下代码

Sys.WebForms.PageRequestManager.getInstance().abortPostBack();