找回密码
 立即注册

QQ登录

只需一步,快速开始

thrall

超级版主

14

主题

174

帖子

2026

积分

超级版主

Rank: 8Rank: 8

积分
2026

活字格认证微信认证勋章

thrall
超级版主   /  发表于:2013-5-3 15:57  /   查看:6808  /  回复:0
使用ASP.NET AJAX框架我们可以搭建快速响应、具有丰富的用户体验的AJAX Web应用程序,而该框架的UpdatePanel控件则提供了一种非常简单的方式来实现Web页面的局部更新,我们不需要在每次回发的时候都加载整个页面。

那这个控件是如何实现这种局部刷新的哪,透过其实现机制我们可以更清楚其优缺点,便于我们确定其使用场合。本文将重点阐述ASP.NET AJAX控件UpdatePanel的实现机制。

1. ASP.NET AJAX 简介 ASP.NET AJAX是微软在ASP.NET 2.0之上对AJAX技术的一个封装,为Web应用程序提供完整的AJAX解决方案。ASP.NET AJAX有两种编程模型:部分更新和远程服务。

部分更新使得用户可以用传统的ASP.NET 2.0应用程序的方式来搭建AJAX应用,具体就是使用UpdatePanel控件来实现无闪烁页面更新。而远程服务则是直接通过前端JavaScript来调用的服务器端服务,前段获取数据后,进行页面更新,这就要求服务器端代码必须分解为特定于应用程序的服务,这是与传统的ASP.NET应用程序完全不同的体系结构。

部分更新着重于对现有应用程序进行渐进式增强,帮助用户逐渐转换到纯粹的AJAX应用。本文主要对部分更新编程模型中核心控件UpdatePanel的实现进行剖析,讲述其背后的故事。

ASP.NET AJAX框架分为客户端以及服务器端两个部分,基于客户端的 Microsoft AJAX Library包含了对浏览器兼容性、网络访问以及客户端控件组件等支持, 而服务器端则包括了服务器控件,Web 服务等等。

见下图:



Microsoft Ajax Library就是ASP.NET AJAX的客户端脚本库,其中MicrosoftAjax.js包含了ASP.NET AJAX的核心内容,包括跨浏览器的支持、基于面向对象对JavaScript的扩展以及网络访问等等。MicrosoftAjaxWebForm.js文件则是完全服务于ASP.NET AJAX页面局部更新这样一个功能的,在该文件中定义了一个客户端对象PageRequestManager,该对象将会负责客户端异步回送的全过程。

2. ScriptManager 和 UpdatePanel ScriptManager和UpdatePanel是ASP.NET AJAX服务器端中最重要的两个控件,ScriptManager控件用来管理ASP.NET页面中的客户端脚本,生成及注册所需要的客户端脚本,通过UpdatePanel控件可以更新页面的指定部分而无需加载整个页面。

看个例子:
  1. <form id="form1" runat="server">
  2.    <asp:ScriptManager ID="ScriptManager1" runat="server">
  3.    </asp:ScriptManager>
  4.    <div>
  5.       <asp:UpdatePanel ID="UpdatePanel1" runat="server">
  6.            <ContentTemplate>
  7.                <%= DateTime.Now %>
  8.                 <br />
  9.                <asp:Button ID="Button1" runat="server" Text="Button" />
  10.            </ContentTemplate>
  11.        </asp:UpdatePanel>
  12.    </div>
  13. </form>
复制代码

构建如上代码所示的页面,在Runtime点击UpdatePanel中的Button控件,则不会引起整个页面刷新,只是用来显示当前时间的Label得到更新。
这是如何实现的哪?

3. ASP.NET AJAX部分呈现剖析

3.1 先从客户端讲起

看一下上面的示例代码在客户端的HTML代码, 这里只列出核心部分,其他全部隐去。
  1. <script type="text/javascript">
  2. //<![CDATA[
  3. Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('form1'));
  4. Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel1'], [], [], 90);
  5. //]]>
  6. </script>

  7. <div id="UpdatePanel1">   
  8.      7/25/2008 4:54:36 PM
  9.      <br />
  10.      <input type="submit" name="Button1" value="Button" id="Button1" />            
  11. </div>
复制代码

看一下上面的两句JavaScript代码,第一句代码中的_initialize 方法是客户端PageRequestManager对象上的静态方法,它会创建一个 PageRequestManager 类的全局实例,并将其初始化。在这个初始化函数中,ageRequestManager对象注册了当前表单对象的submit事件,以及window对象的load和unload事件。

而第二句代码则是通过PageRequestManager的getInstance方法来检索其唯一实例, 得到该实例后调用_updateControls方法来注册UpdatePanel以及其Trigger控件。

我们可以从MicrosoftAjaxWebForm.js文件中得到_updateControls方法的声明:
  1. function Sys$WebForms$PageRequestManager$_updateControls(updatePanelIDs, asyncPostBackControlIDs, postBackControlIDs, asyncPostBackTimeout) {}
复制代码

由其中第一个参数代表了当前页面上所有的UpdatePanel控件的ID集合,如果该UpdatePanel的ChildrenAsTrigger为True的话,应在ID前添加字符't',否则添加字符'f';而第二个参数是所有引发异步回送的控件ID;第三个参数是所有引发同步回送的控件ID;第四个参数设定了异步回送的Timeout时间,单位为秒。于PageRequestManager对象注册了当前表单的submit时间,所以每当页面有提交动作的时候,PageRequestManager对象就会介入,看一下PageRequestManager对象页面提交处理函数_onFormSubmit(evt)。

如果需要执行一次异步回送的话,会中止原有的普通浏览器会回发,代之使用XMLHttpRequest进行AJAX回发。在封装这个请求的时候,当前页面的所有字段以及视图状态都会被打包在请求中,另外还设置了这次Request的HTTP头:request.get_headers()['X-MicrosoftAjax'] = 'Delta=true';

在服务器端将会根据这个HTTP头标记来判定是否为一次AJAX异步回发。

_onFormSubmit(evt)函数代码:
  1. function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
  2.         var continueSubmit = true;
  3.         var isCrossPost = this._isCrossPost;
  4.         this._isCrossPost = false;
  5.         if (this._onsubmit) {
  6.             continueSubmit = this._onsubmit();
  7.         }
  8.         if (continueSubmit) {
  9.             for (var i = 0; i < this._onSubmitStatements.length; i++) {
  10.                 if (!this._onSubmitStatements[i]()) {
  11.                     continueSubmit = false;
  12.                     break;
  13.                 }
  14.             }
  15.         }
  16.         if (!continueSubmit) {
  17.             if (evt) {
  18.                 evt.preventDefault();
  19.             }
  20.             return;
  21.         }
  22.         var form = this._form;
  23.         if (isCrossPost) {
  24.             return;
  25.         }
  26.         if (this._activeDefaultButton &amp;&amp; !this._activeDefaultButtonClicked) {
  27.             this._onFormElementActive(this._activeDefaultButton, 0, 0);
  28.         }
  29.         if (!this._postBackSettings.async) {
  30.             return;
  31.         }
  32.         var formBody = new Sys.StringBuilder();
  33.         formBody.append(encodeURIComponent(this._scriptManagerID) + '=' + encodeURIComponent(this._postBackSettings.panelID) + '&amp;');
  34.         var count = form.elements.length;
  35.         for (var i = 0; i < count; i++) {
  36.             var element = form.elements[i];
  37.             var name = element.name;
  38.             if (typeof(name) === "undefined" || (name === null) || (name.length === 0)) {
  39.                 continue;
  40.             }
  41.             var tagName = element.tagName;
  42.             if (tagName === 'INPUT') {
  43.                 var type = element.type;
  44.                 if ((type === 'text') ||
  45.                     (type === 'password') ||
  46.                     (type === 'hidden') ||
  47.                     (((type === 'checkbox') || (type === 'radio')) &amp;&amp; element.checked)) {
  48.                     formBody.append(encodeURIComponent(name));
  49.                     formBody.append('=');
  50.                     formBody.append(encodeURIComponent(element.value));
  51.                     formBody.append('&amp;');
  52.                 }
  53.             }
  54.             else if (tagName === 'SELECT') {
  55.                 var optionCount = element.options.length;
  56.                 for (var j = 0; j < optionCount; j++) {
  57.                     var option = element.options[j];
  58.                     if (option.selected) {
  59.                         formBody.append(encodeURIComponent(name));
  60.                         formBody.append('=');
  61.                         formBody.append(encodeURIComponent(option.value));
  62.                         formBody.append('&amp;');
  63.                     }
  64.                 }
  65.             }
  66.             else if (tagName === 'TEXTAREA') {
  67.                 formBody.append(encodeURIComponent(name));
  68.                 formBody.append('=');
  69.                 formBody.append(encodeURIComponent(element.value));
  70.                 formBody.append('&amp;');
  71.             }
  72.         }
  73.         if (this._additionalInput) {
  74.             formBody.append(this._additionalInput);
  75.             this._additionalInput = null;
  76.         }
  77.         
  78.         var request = new Sys.Net.WebRequest();
  79.         var action = form.action;
  80.         if (Sys.Browser.agent === Sys.Browser.InternetExplorer) {
  81.             var queryIndex = action.indexOf('?');
  82.             if (queryIndex !== -1) {
  83.                 var path = action.substr(0, queryIndex);
  84.                 if (path.indexOf("%") === -1) {
  85.                     action = encodeURI(path) + action.substr(queryIndex);
  86.                 }
  87.             }
  88.             else if (action.indexOf("%") === -1) {
  89.                 action = encodeURI(action);
  90.             }
  91.         }
  92.         request.set_url(action);
  93.         request.get_headers()['X-MicrosoftAjax'] = 'Delta=true';
  94.         request.get_headers()['Cache-Control'] = 'no-cache';
  95.         request.set_timeout(this._asyncPostBackTimeout);
  96.         request.add_completed(Function.createDelegate(this, this._onFormSubmitCompleted));
  97.         request.set_body(formBody.toString());
  98.         var handler = this._get_eventHandlerList().getHandler("initializeRequest");
  99.         if (handler) {
  100.             var eventArgs = new Sys.WebForms.InitializeRequestEventArgs(request, this._postBackSettings.sourceElement);
  101.             handler(this, eventArgs);
  102.             continueSubmit = !eventArgs.get_cancel();
  103.         }
  104.         if (!continueSubmit) {
  105.             if (evt) {
  106.                 evt.preventDefault();
  107.             }
  108.             return;
  109.         }
  110.         this._scrollPosition = this._getScrollPosition();
  111.         this.abortPostBack();
  112.         handler = this._get_eventHandlerList().getHandler("beginRequest");
  113.         if (handler) {
  114.             var eventArgs = new Sys.WebForms.BeginRequestEventArgs(request, this._postBackSettings.sourceElement);
  115.             handler(this, eventArgs);
  116.         }
  117.         
  118.         if (this._originalDoCallback) {
  119.             this._cancelPendingCallbacks();
  120.         }
  121.         this._request = request;
  122.         request.invoke();
  123.         if (evt) {
  124.             evt.preventDefault();
  125.         }
  126.     }
复制代码

我们可以发现AJAX回发所提交的数据量其实跟普通回发过程中提交的数据量是一样的,并且还附加了一些额外信息。

3.2 服务器端的处理

AJAX回发请求到达服务器之后,当前页面的生命周期跟普通回发引起的请求是一样的,页面的Init、Load和Render等等事件都会被触发,差别只是在于AJAX回发使用了不同的呈现画法。

AJAX回发引起的请求生命周期:


从上图我们可以看到,页面的生命周期与普通回发是一样的,同样页面上的控件也会经历相应的生命周期。
先了解一下ScriptManager控件在服务器端的处理:

- OnInit:在Init事件中,ScriptManager控件会注册页面的InitComplete, PreRenderComplete以及PreRender事件,另外还会根据本次请求的HTTP头来设定一个标记以确定本次回发是否为Ajax异步更新所引起的回发。

见下面的代码:
  1. protected internal override void OnInit(EventArgs e)
  2. {
  3.     base.OnInit(e);
  4.     if (this.EnableHistory)
  5.     {
  6.         this.RegisterAsyncPostBackControl(this);
  7.     }
  8.     if (!base.DesignMode)
  9.     {
  10.         IPage iPage = this.IPage;
  11.         if (GetCurrent(this.Page) != null)
  12.         {
  13.             throw new InvalidOperationException(AtlasWeb.ScriptManager_OnlyOneScriptManager);
  14.         }
  15.         iPage.Items[typeof(IScriptManager)] = this;
  16.         iPage.Items[typeof(ScriptManager)] = this;
  17.         iPage.InitComplete += new EventHandler(this.OnPageInitComplete);
  18.         iPage.PreRenderComplete += new EventHandler(this.OnPagePreRenderComplete);
  19.         if (iPage.IsPostBack)
  20.         {
  21.             this._isInAsyncPostBack = PageRequestManager.IsAsyncPostBackRequest(iPage.Request.Headers);
  22.             if (this.EnableHistory)
  23.             {
  24.                 this._isNavigating = iPage.Request["__EVENTTARGET"] == this.UniqueID;
  25.             }
  26.         }
  27.         this.PageRequestManager.OnInit();
  28.         iPage.PreRender += new EventHandler(this.ScriptControlManager.OnPagePreRender);
  29.     }
  30. }
复制代码

- OnPagePreRenderComplete,在PagePreRenderComplete事件中,ScriptManager控件会注册脚本文件以及Services代理脚本,MicrosoftAjax.js和MicrosoftAjaxWebForm.js就是在这个阶段被注册到客户端的。

见下面的代码:
  1. private void OnPagePreRenderComplete(object sender, EventArgs e)
  2. {
  3.     if (!this.IsInAsyncPostBack)
  4.     {
  5.         if (this.SupportsPartialRendering)
  6.         {
  7.             this.IPage.ClientScript.GetPostBackEventReference(new PostBackOptions(this, null, null, false, false, false, false, true, null));
  8.         }
  9.         this.RegisterGlobalizationScriptBlock();
  10.         this.RegisterScripts();
  11.         this.RegisterServices();
  12.         if (this.EnableHistory)
  13.         {
  14.             JavaScriptSerializer serializer = JavaScriptSerializer.CreateInstance();
  15.             string[] strArray = new string[] { "\r\nSys.Application.setServerId(", serializer.Serialize(this.ClientID), ", ", serializer.Serialize(this.UniqueID), ");\r\n", ((this._initialState != null) &amp;&amp; (this._initialState.Count != 0)) ? ("  Sys.Application.setServerState('" + this.GetStateString() + "');\r\n") : "\r\n" };
  16.             string script = string.Concat(strArray);
  17.             RegisterStartupScript(this, typeof(ScriptManager), "HistoryStartup", script, true);
  18.         }
  19.     }
  20.     else
  21.     {
  22.         this.RegisterScripts();
  23.         if (this.EnableHistory)
  24.         {
  25.             if ((this._initialState != null) &amp;&amp; (this._initialState.Count == 0))
  26.             {
  27.                 this._initialState = null;
  28.             }
  29.             if (this._newPointCreated)
  30.             {
  31.                 this.RegisterDataItem(this, "'" + this.GetStateString() + "'", true);
  32.             }
  33.         }
  34.     }
  35. }
复制代码

- OnPreRender,在PreRender事件中如果判定本次回发为AJAX回发,则会调用PageRequestManager对象的OnPreRender方法。而PageRequestManager对象则会调用Page对象的SetRenderMethodDelegate方法来代理Page的画法,PageRequestManager对象会真正负责本次AJAX回发最终的HTML代码。
见下面的代码:

  1. public class ScriptManager : Control,
  2. {
  3.    protected internal override void OnPreRender(EventArgs e)
  4.    {
  5.        base.OnPreRender(e);
  6.        if (this.IsInAsyncPostBack)
  7.        {
  8.            this.PageRequestManager.OnPreRender();
  9.        }
  10.    }
  11. }

  12. internal sealed class PageRequestManager
  13. {
  14.    internal void OnPreRender()
  15.    {
  16.         this._owner.IPage.SetRenderMethodDelegate(new RenderMethod(this.RenderPageCallback));
  17.    }
  18. }
复制代码

PageRequestManager的RenderPageCallback方法最终处理了AJAX回发所需要的HTML代码,在这个方法中会遍历页面上所有涉及到的UpdatePanel控件,得到其更新后的HTML代码后,与隐藏字段还有一些额外信息一起打包,然后传递给客户端。

见下面的代码:
  1. private void RenderPageCallback(HtmlTextWriter writer, Control pageControl)
  2. {
  3.     this.ProcessUpdatePanels();
  4.     IHttpResponse response = this._owner.IPage.Response;
  5.     response.ContentType = "text/plain";
  6.     response.Cache.SetNoServerCaching();
  7.     IHtmlForm form = this._owner.IPage.Form;
  8.     form.SetRenderMethodDelegate(new RenderMethod(this.RenderFormCallback));
  9.     this._updatePanelWriter = writer;
  10.     ParserStringWriter writer2 = new ParserStringWriter();
  11.     ParserHtmlTextWriter writer3 = new ParserHtmlTextWriter(writer2);
  12.     writer2.ParseWrites = true;
  13.     form.RenderControl(writer3);
  14.     writer2.ParseWrites = false;
  15.     foreach (KeyValuePair<string, string> pair in writer2.HiddenFields)
  16.     {
  17.         if (ControlUtil.IsBuiltInHiddenField(pair.Key))
  18.         {
  19.             EncodeString(writer, "hiddenField", pair.Key, pair.Value);
  20.         }
  21.     }
  22.     EncodeString(writer, "asyncPostBackControlIDs", string.Empty, this.GetAsyncPostBackControlIDs(false));
  23.     EncodeString(writer, "postBackControlIDs", string.Empty, this.GetPostBackControlIDs(false));
  24.     EncodeString(writer, "updatePanelIDs", string.Empty, this.GetAllUpdatePanelIDs());
  25.     EncodeString(writer, "childUpdatePanelIDs", string.Empty, this.GetChildUpdatePanelIDs());
  26.     EncodeString(writer, "panelsToRefreshIDs", string.Empty, this.GetRefreshingUpdatePanelIDs());
  27.     EncodeString(writer, "asyncPostBackTimeout", string.Empty, this._owner.AsyncPostBackTimeout.ToString(CultureInfo.InvariantCulture));
  28.     if (writer3.FormAction != null)
  29.     {
  30.         EncodeString(writer, "formAction", string.Empty, writer3.FormAction);
  31.     }
  32.     if (this._owner.IPage.Header != null)
  33.     {
  34.         string title = this._owner.IPage.Title;
  35.         if (!string.IsNullOrEmpty(title))
  36.         {
  37.             EncodeString(writer, "pageTitle", string.Empty, title);
  38.         }
  39.     }
  40.     this.RenderDataItems(writer);
  41.     this.ProcessScriptRegistration(writer);
  42.     this.ProcessFocus(writer);
  43. }
复制代码

3.3 客户端更新
当服务器端相应完毕后,客户端会得到响应信息,然后调用客户端对象PageRequestManager的_onFormSubmitCompleted方法来进行页面局部更新,最终会调用_updatePanel方法来更新UpdatePanel控件。

参见_onFormSubmitCompleted方法的代码:

  1. function Sys$WebForms$PageRequestManager$_onFormSubmitCompleted(sender, eventArgs) {
  2.         this._processingRequest = true;
  3.         var delimitByLengthDelimiter = '|';
  4.         if (sender.get_timedOut()) {
  5.             this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);
  6.             return;
  7.         }
  8.         if (sender.get_aborted()) {
  9.             this._endPostBack(null, sender);
  10.             return;
  11.         }
  12.         if (!this._request || sender.get_webRequest() !== this._request) {
  13.             return;
  14.         }
  15.         var errorMessage;
  16.         var delta = [];
  17.         if (sender.get_statusCode() !== 200) {
  18.             this._endPostBack(this._createPageRequestManagerServerError(sender.get_statusCode()), sender);
  19.             return;
  20.         }
  21.         var reply = sender.get_responseData();
  22.         var delimiterIndex, len, type, id, content;
  23.         var replyIndex = 0;
  24.         var parserErrorDetails = null;
  25.         while (replyIndex < reply.length) {
  26.             delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
  27.             if (delimiterIndex === -1) {
  28.                 parserErrorDetails = this._findText(reply, replyIndex);
  29.                 break;
  30.             }
  31.             len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);
  32.             if ((len % 1) !== 0) {
  33.                 parserErrorDetails = this._findText(reply, replyIndex);
  34.                 break;
  35.             }
  36.             replyIndex = delimiterIndex + 1;
  37.             delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
  38.             if (delimiterIndex === -1) {
  39.                 parserErrorDetails = this._findText(reply, replyIndex);
  40.                 break;
  41.             }
  42.             type = reply.substring(replyIndex, delimiterIndex);
  43.             replyIndex = delimiterIndex + 1;
  44.             delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
  45.             if (delimiterIndex === -1) {
  46.                 parserErrorDetails = this._findText(reply, replyIndex);
  47.                 break;
  48.             }
  49.             id = reply.substring(replyIndex, delimiterIndex);
  50.             replyIndex = delimiterIndex + 1;
  51.             if ((replyIndex + len) >= reply.length) {
  52.                 parserErrorDetails = this._findText(reply, reply.length);
  53.                 break;
  54.             }
  55.             content = reply.substr(replyIndex, len);
  56.             replyIndex += len;
  57.             if (reply.charAt(replyIndex) !== delimitByLengthDelimiter) {
  58.                 parserErrorDetails = this._findText(reply, replyIndex);
  59.                 break;
  60.             }
  61.             replyIndex++;
  62.             Array.add(delta, {type: type, id: id, content: content});
  63.         }
  64.         if (parserErrorDetails) {
  65.             this._endPostBack(this._createPageRequestManagerParserError(String.format(Sys.WebForms.Res.PRM_ParserErrorDetails, parserErrorDetails)), sender);
  66.             return;
  67.         }
  68.         var updatePanelNodes = [];
  69.         var hiddenFieldNodes = [];
  70.         var arrayDeclarationNodes = [];
  71.         var scriptBlockNodes = [];
  72.         var scriptStartupNodes = [];
  73.         var expandoNodes = [];
  74.         var onSubmitNodes = [];
  75.         var dataItemNodes = [];
  76.         var dataItemJsonNodes = [];
  77.         var scriptDisposeNodes = [];
  78.         var asyncPostBackControlIDsNode, postBackControlIDsNode,
  79.             updatePanelIDsNode, asyncPostBackTimeoutNode,
  80.             childUpdatePanelIDsNode, panelsToRefreshNode, formActionNode;
  81.         for (var i = 0; i < delta.length; i++) {
  82.             var deltaNode = delta[i];
  83.             switch (deltaNode.type) {
  84.                 case "updatePanel":
  85.                     Array.add(updatePanelNodes, deltaNode);
  86.                     break;
  87.                 case "hiddenField":
  88.                     Array.add(hiddenFieldNodes, deltaNode);
  89.                     break;
  90.                 case "arrayDeclaration":
  91.                     Array.add(arrayDeclarationNodes, deltaNode);
  92.                     break;
  93.                 case "scriptBlock":
  94.                     Array.add(scriptBlockNodes, deltaNode);
  95.                     break;
  96.                 case "scriptStartupBlock":
  97.                     Array.add(scriptStartupNodes, deltaNode);
  98.                     break;
  99.                 case "expando":
  100.                     Array.add(expandoNodes, deltaNode);
  101.                     break;
  102.                 case "onSubmit":
  103.                     Array.add(onSubmitNodes, deltaNode);
  104.                     break;
  105.                 case "asyncPostBackControlIDs":
  106.                     asyncPostBackControlIDsNode = deltaNode;
  107.                     break;
  108.                 case "postBackControlIDs":
  109.                     postBackControlIDsNode = deltaNode;
  110.                     break;
  111.                 case "updatePanelIDs":
  112.                     updatePanelIDsNode = deltaNode;
  113.                     break;
  114.                 case "asyncPostBackTimeout":
  115.                     asyncPostBackTimeoutNode = deltaNode;
  116.                     break;
  117.                 case "childUpdatePanelIDs":
  118.                     childUpdatePanelIDsNode = deltaNode;
  119.                     break;
  120.                 case "panelsToRefreshIDs":
  121.                     panelsToRefreshNode = deltaNode;
  122.                     break;
  123.                 case "formAction":
  124.                     formActionNode = deltaNode;
  125.                     break;
  126.                 case "dataItem":
  127.                     Array.add(dataItemNodes, deltaNode);
  128.                     break;
  129.                 case "dataItemJson":
  130.                     Array.add(dataItemJsonNodes, deltaNode);
  131.                     break;
  132.                 case "scriptDispose":
  133.                     Array.add(scriptDisposeNodes, deltaNode);
  134.                     break;
  135.                 case "pageRedirect":
  136.                     if (Sys.Browser.agent === Sys.Browser.InternetExplorer) {
  137.                         var anchor = document.createElement("a");
  138.                         anchor.style.display = 'none';
  139.                         anchor.attachEvent("onclick", cancelBubble);
  140.                         anchor.href = deltaNode.content;
  141.                         document.body.appendChild(anchor);
  142.                         anchor.click();
  143.                         anchor.detachEvent("onclick", cancelBubble);
  144.                         document.body.removeChild(anchor);
  145.                         
  146.                         function cancelBubble(e) {
  147.                             e.cancelBubble = true;
  148.                         }
  149.                     }
  150.                     else {
  151.                         window.location.href = deltaNode.content;
  152.                     }
  153.                     return;
  154.                 case "error":
  155.                     this._endPostBack(this._createPageRequestManagerServerError(Number.parseInvariant(deltaNode.id), deltaNode.content), sender);
  156.                     return;
  157.                 case "pageTitle":
  158.                     document.title = deltaNode.content;
  159.                     break;
  160.                 case "focus":
  161.                     this._controlIDToFocus = deltaNode.content;
  162.                     break;
  163.                 default:
  164.                     this._endPostBack(this._createPageRequestManagerParserError(String.format(Sys.WebForms.Res.PRM_UnknownToken, deltaNode.type)), sender);
  165.                     return;
  166.             }
  167.         }
  168.         var i;
  169.         if (asyncPostBackControlIDsNode &amp;&amp; postBackControlIDsNode &amp;&amp;
  170.             updatePanelIDsNode &amp;&amp; panelsToRefreshNode &amp;&amp;
  171.             asyncPostBackTimeoutNode &amp;&amp; childUpdatePanelIDsNode) {
  172.             this._oldUpdatePanelIDs = this._updatePanelIDs;
  173.             var childUpdatePanelIDsString = childUpdatePanelIDsNode.content;
  174.             this._childUpdatePanelIDs = childUpdatePanelIDsString.length ? childUpdatePanelIDsString.split(',') : [];
  175.             var asyncPostBackControlIDsArray = this._splitNodeIntoArray(asyncPostBackControlIDsNode);
  176.             var postBackControlIDsArray = this._splitNodeIntoArray(postBackControlIDsNode);
  177.             var updatePanelIDsArray = this._splitNodeIntoArray(updatePanelIDsNode);
  178.             this._panelsToRefreshIDs = this._splitNodeIntoArray(panelsToRefreshNode);
  179.             for (i = 0; i < this._panelsToRefreshIDs.length; i++) {
  180.                 var panelClientID = this._uniqueIDToClientID(this._panelsToRefreshIDs[i]);
  181.                 if (!document.getElementById(panelClientID)) {
  182.                     this._endPostBack(Error.invalidOperation(String.format(Sys.WebForms.Res.PRM_MissingPanel, panelClientID)), sender);
  183.                     return;
  184.                 }
  185.             }
  186.             var asyncPostBackTimeout = asyncPostBackTimeoutNode.content;
  187.             this._updateControls(updatePanelIDsArray, asyncPostBackControlIDsArray, postBackControlIDsArray, asyncPostBackTimeout);
  188.         }
  189.         this._dataItems = {};
  190.         for (i = 0; i < dataItemNodes.length; i++) {
  191.             var dataItemNode = dataItemNodes[i];
  192.             this._dataItems[dataItemNode.id] = dataItemNode.content;
  193.         }
  194.         for (i = 0; i < dataItemJsonNodes.length; i++) {
  195.             var dataItemJsonNode = dataItemJsonNodes[i];
  196.             this._dataItems[dataItemJsonNode.id] = Sys.Serialization.JavaScriptSerializer.deserialize(dataItemJsonNode.content);
  197.         }
  198.         var handler = this._get_eventHandlerList().getHandler("pageLoading");
  199.         if (handler) {
  200.             handler(this, this._getPageLoadingEventArgs());
  201.         }
  202.         if (formActionNode) {
  203.             this._form.action = formActionNode.content;
  204.         }
  205.         
  206.         
  207.         Sys._ScriptLoader.readLoadedScripts();
  208.         Sys.Application.beginCreateComponents();
  209.         var scriptLoader = Sys._ScriptLoader.getInstance();
  210.         this._queueScripts(scriptLoader, scriptBlockNodes, true, false);
  211.         
  212.         this._updateContext = {
  213.             response: sender,
  214.             updatePanelNodes: updatePanelNodes,
  215.             scriptBlockNodes: scriptBlockNodes,
  216.             scriptDisposeNodes: scriptDisposeNodes,
  217.             hiddenFieldNodes: hiddenFieldNodes,
  218.             arrayDeclarationNodes: arrayDeclarationNodes,
  219.             expandoNodes: expandoNodes,
  220.             scriptStartupNodes: scriptStartupNodes,
  221.             onSubmitNodes: onSubmitNodes
  222.         };
  223.         scriptLoader.loadScripts(0,
  224.             Function.createDelegate(this, this._scriptIncludesLoadComplete),
  225.             Function.createDelegate(this, this._scriptIncludesLoadFailed),
  226.             null);
  227. }
复制代码

4.结语

使用UpdatePanel是给已经存在的ASP.NET应用程序添加AJAX体验的最快捷方式,对于应用程序的架构也不会有影响,我们可以使用它来逐步的提高应用程序的用户体验。但是其性能与纯粹的AJAX方式相比较,还是比较差的。

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部