`
wangxiaohigh
  • 浏览: 1419399 次
文章分类
社区版块
存档分类
最新评论

ASP.NET AJAX UpdatePanel 控件实现剖析

 
阅读更多

使用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控件可以更新页面的指定部分而无需加载整个页面。

看个例子:

01 <form id="form1" runat="server">
02 <asp:ScriptManager ID="ScriptManager1" runat="server">
03 </asp:ScriptManager>
04 <div>
05 <asp:UpdatePanel ID="UpdatePanel1" runat="server">
06 <ContentTemplate>
07 <%= DateTime.Now %>
08 <br />
09 <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代码, 这里只列出核心部分,其他全部隐去。

01 <script type="text/javascript">
02 //<![CDATA[
03 Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('form1'));
04 Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel1'], [], [], 90);
05 //]]>
06 </script>
07
08 <div id="UpdatePanel1">
09 7/25/2008 4:54:36 PM
10 <br />
11 <input type="submit" name="Button1" value="Button" id="Button1" />
12 </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)函数代码:

001 function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
002 var continueSubmit = true;
003 var isCrossPost = this._isCrossPost;
004 this._isCrossPost = false;
005 if (this._onsubmit) {
006 continueSubmit = this._onsubmit();
007 }
008 if (continueSubmit) {
009 for (var i = 0; i < this._onSubmitStatements.length; i++) {
010 if (!this._onSubmitStatements[i]()) {
011 continueSubmit = false;
012 break;
013 }
014 }
015 }
016 if (!continueSubmit) {
017 if (evt) {
018 evt.preventDefault();
019 }
020 return;
021 }
022 var form = this._form;
023 if (isCrossPost) {
024 return;
025 }
026 if (this._activeDefaultButton && !this._activeDefaultButtonClicked) {
027 this._onFormElementActive(this._activeDefaultButton, 0, 0);
028 }
029 if (!this._postBackSettings.async) {
030 return;
031 }
032 var formBody = new Sys.StringBuilder();
033 formBody.append(encodeURIComponent(this._scriptManagerID) + '=' + encodeURIComponent(this._postBackSettings.panelID) + '&');
034 var count = form.elements.length;
035 for (var i = 0; i < count; i++) {
036 var element = form.elements[i];
037 var name = element.name;
038 if (typeof(name) === "undefined" || (name === null) || (name.length === 0)) {
039 continue;
040 }
041 var tagName = element.tagName;
042 if (tagName === 'INPUT') {
043 var type = element.type;
044 if ((type === 'text') ||
045 (type === 'password') ||
046 (type === 'hidden') ||
047 (((type === 'checkbox') || (type === 'radio')) && element.checked)) {
048 formBody.append(encodeURIComponent(name));
049 formBody.append('=');
050 formBody.append(encodeURIComponent(element.value));
051 formBody.append('&');
052 }
053 }
054 else if (tagName === 'SELECT') {
055 var optionCount = element.options.length;
056 for (var j = 0; j < optionCount; j++) {
057 var option = element.options[j];
058 if (option.selected) {
059 formBody.append(encodeURIComponent(name));
060 formBody.append('=');
061 formBody.append(encodeURIComponent(option.value));
062 formBody.append('&');
063 }
064 }
065 }
066 else if (tagName === 'TEXTAREA') {
067 formBody.append(encodeURIComponent(name));
068 formBody.append('=');
069 formBody.append(encodeURIComponent(element.value));
070 formBody.append('&');
071 }
072 }
073 if (this._additionalInput) {
074 formBody.append(this._additionalInput);
075 this._additionalInput = null;
076 }
077
078 var request = new Sys.Net.WebRequest();
079 var action = form.action;
080 if (Sys.Browser.agent === Sys.Browser.InternetExplorer) {
081 var queryIndex = action.indexOf('?');
082 if (queryIndex !== -1) {
083 var path = action.substr(0, queryIndex);
084 if (path.indexOf("%") === -1) {
085 action = encodeURI(path) + action.substr(queryIndex);
086 }
087 }
088 else if (action.indexOf("%") === -1) {
089 action = encodeURI(action);
090 }
091 }
092 request.set_url(action);
093 request.get_headers()['X-MicrosoftAjax'] = 'Delta=true';
094 request.get_headers()['Cache-Control'] = 'no-cache';
095 request.set_timeout(this._asyncPostBackTimeout);
096 request.add_completed(Function.createDelegate(this, this._onFormSubmitCompleted));
097 request.set_body(formBody.toString());
098 var handler = this._get_eventHandlerList().getHandler("initializeRequest");
099 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异步更新所引起的回发。

见下面的代码:

01 protected internal override void OnInit(EventArgs e)
02 {
03 base.OnInit(e);
04 if (this.EnableHistory)
05 {
06 this.RegisterAsyncPostBackControl(this);
07 }
08 if (!base.DesignMode)
09 {
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就是在这个阶段被注册到客户端的。

见下面的代码:

01 private void OnPagePreRenderComplete(object sender, EventArgs e)
02 {
03 if (!this.IsInAsyncPostBack)
04 {
05 if (this.SupportsPartialRendering)
06 {
07 this.IPage.ClientScript.GetPostBackEventReference(new PostBackOptions(this, null, null, false, false, false, false, true, null));
08 }
09 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) && (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) && (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代码。

见下面的代码:

01 public class ScriptManager : Control,
02 {
03 protected internal override void OnPreRender(EventArgs e)
04 {
05 base.OnPreRender(e);
06 if (this.IsInAsyncPostBack)
07 {
08 this.PageRequestManager.OnPreRender();
09 }
10 }
11 }
12
13 internal sealed class PageRequestManager
14 {
15 internal void OnPreRender()
16 {
17 this._owner.IPage.SetRenderMethodDelegate(new RenderMethod(this.RenderPageCallback));
18 }
19 }

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

见下面的代码:

01 private void RenderPageCallback(HtmlTextWriter writer, Control pageControl)
02 {
03 this.ProcessUpdatePanels();
04 IHttpResponse response = this._owner.IPage.Response;
05 response.ContentType = "text/plain";
06 response.Cache.SetNoServerCaching();
07 IHtmlForm form = this._owner.IPage.Form;
08 form.SetRenderMethodDelegate(new RenderMethod(this.RenderFormCallback));
09 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方法的代码:

001 function Sys$WebForms$PageRequestManager$_onFormSubmitCompleted(sender, eventArgs) {
002 this._processingRequest = true;
003 var delimitByLengthDelimiter = '|';
004 if (sender.get_timedOut()) {
005 this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);
006 return;
007 }
008 if (sender.get_aborted()) {
009 this._endPostBack(null, sender);
010 return;
011 }
012 if (!this._request || sender.get_webRequest() !== this._request) {
013 return;
014 }
015 var errorMessage;
016 var delta = [];
017 if (sender.get_statusCode() !== 200) {
018 this._endPostBack(this._createPageRequestManagerServerError(sender.get_statusCode()), sender);
019 return;
020 }
021 var reply = sender.get_responseData();
022 var delimiterIndex, len, type, id, content;
023 var replyIndex = 0;
024 var parserErrorDetails = null;
025 while (replyIndex < reply.length) {
026 delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
027 if (delimiterIndex === -1) {
028 parserErrorDetails = this._findText(reply, replyIndex);
029 break;
030 }
031 len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);
032 if ((len % 1) !== 0) {
033 parserErrorDetails = this._findText(reply, replyIndex);
034 break;
035 }
036 replyIndex = delimiterIndex + 1;
037 delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
038 if (delimiterIndex === -1) {
039 parserErrorDetails = this._findText(reply, replyIndex);
040 break;
041 }
042 type = reply.substring(replyIndex, delimiterIndex);
043 replyIndex = delimiterIndex + 1;
044 delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
045 if (delimiterIndex === -1) {
046 parserErrorDetails = this._findText(reply, replyIndex);
047 break;
048 }
049 id = reply.substring(replyIndex, delimiterIndex);
050 replyIndex = delimiterIndex + 1;
051 if ((replyIndex + len) >= reply.length) {
052 parserErrorDetails = this._findText(reply, reply.length);
053 break;
054 }
055 content = reply.substr(replyIndex, len);
056 replyIndex += len;
057 if (reply.charAt(replyIndex) !== delimitByLengthDelimiter) {
058 parserErrorDetails = this._findText(reply, replyIndex);
059 break;
060 }
061 replyIndex++;
062 Array.add(delta, {type: type, id: id, content: content});
063 }
064 if (parserErrorDetails) {
065 this._endPostBack(this._createPageRequestManagerParserError(String.format(Sys.WebForms.Res.PRM_ParserErrorDetails, parserErrorDetails)), sender);
066 return;
067 }
068 var updatePanelNodes = [];
069 var hiddenFieldNodes = [];
070 var arrayDeclarationNodes = [];
071 var scriptBlockNodes = [];
072 var scriptStartupNodes = [];
073 var expandoNodes = [];
074 var onSubmitNodes = [];
075 var dataItemNodes = [];
076 var dataItemJsonNodes = [];
077 var scriptDisposeNodes = [];
078 var asyncPostBackControlIDsNode, postBackControlIDsNode,
079 updatePanelIDsNode, asyncPostBackTimeoutNode,
080 childUpdatePanelIDsNode, panelsToRefreshNode, formActionNode;
081 for (var i = 0; i < delta.length; i++) {
082 var deltaNode = delta[i];
083 switch (deltaNode.type) {
084 case "updatePanel":
085 Array.add(updatePanelNodes, deltaNode);
086 break;
087 case "hiddenField":
088 Array.add(hiddenFieldNodes, deltaNode);
089 break;
090 case "arrayDeclaration":
091 Array.add(arrayDeclarationNodes, deltaNode);
092 break;
093 case "scriptBlock":
094 Array.add(scriptBlockNodes, deltaNode);
095 break;
096 case "scriptStartupBlock":
097 Array.add(scriptStartupNodes, deltaNode);
098 break;
099 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 && postBackControlIDsNode &&
170 updatePanelIDsNode && panelsToRefreshNode &&
171 asyncPostBackTimeoutNode && 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方式相比较,还是比较差的。

分享到:
评论

相关推荐

    ASP.NET AJAX实战源码

    5.3.3 利用ASP.NET AJAX实现内容集成 125 5.3.4 桥技术 131 5.4 使用ASP.NET应用服务 137 5.4.1 启用ASP.NET应用服务 137 5.4.2 验证服务 138 5.4.3 个性化 140 5.4.4 角色:Orcas预览 143 5.4.5 消息板应用...

    [ASP.NET.AJAX编程参考手册(涵盖ASP.NET.3.5及2.0)].(美)霍斯拉维.扫描版.pdf

    本书通过大量实例、深入的描述以及代码分析,全面涵盖了ASP.NET AJAX服务器端和客户端框架。书中的所有代码都通过了ASP.NET 2.0和ASP.NET 3.5的测试。通过本书,您将学习到这些框架之间是如何进行协同以满足AJAx...

    ASP.NET3.5从入门到精通

    16.2 ASP.NET 3.5AJAX 控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress)...

    ASP.NET 3.5 开发大全

    16.2 ASP.NET 3.5AJAX控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress) ...

    ASP.NET 3.5 开发大全word课件

    16.2 ASP.NET 3.5AJAX控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress) ...

    ASP.NET 3.5 开发大全11-15

    16.2 ASP.NET 3.5AJAX控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress) ...

    ASP.NET 3.5 开发大全1-5

    16.2 ASP.NET 3.5AJAX控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress) ...

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    此外,《ASP.NET 4高级程序设计(第4版)》专门提供了两章的内容来教你如何用Ajax 技术制作快速响应的页面,以及如何使用微软的ASP.NETAJAX平台。另外,还专门介绍了ASP.NET4 新增的功能,如MVC 和动态数据等。  ...

    ASP.NET4高级程序设计(第4版) 3/3

    此外,《ASP.NET 4高级程序设计(第4版)》专门提供了两章的内容来教你如何用Ajax 技术制作快速响应的页面,以及如何使用微软的ASP.NETAJAX平台。另外,还专门介绍了ASP.NET4 新增的功能,如MVC 和动态数据等。  ...

    史上最好传智播客就业班.net培训教程60G 不下会后悔

    再比如ASP.Net内置的AJAX解决方案UpdatePanel只在部分要求不高的内网项目中才被使用,因此我们在讲解UpdatePanel的使用和原理之外,把更多的时间放在讲解企业中用的最多的JQuery AJAX解决方案上。 6、B/S系统项目(7...

    ASPNET35开发大全第一章

    16.2 ASP.NET 3.5AJAX控件 16.2.1 脚本管理控件(ScriptManger) 16.2.2 脚本管理控件(ScriptMangerProxy) 16.2.3 时间控件(Timer) 16.2.4 更新区域控件(UpdatePanel) 16.2.5 更新进度控件(UpdateProgress) ...

    Visual.Basic.2010.&.NET4.高级编程(第6版)-文字版.pdf

    4.6.6 在asp.net中引用名称空间 241 4.7 创建自己的名称空间 241 4.8 my关键字 244 4.8.1 my.application名称空间 244 4.8.2 my.computer名称空间 248 4.8.3 my.forms名称空间 251 4.8.4 my.resources...

Global site tag (gtag.js) - Google Analytics