Atlas 实现机制浅析 [2]

时间:2022-10-10 04:48:42

原文:http://www.blogcn.com/User8/flier_lu/blog/28981917.html

1.2 UpdatePanel 与局部重绘模式 (Partial Rendering Mode)

   在上一节介绍 Altas 整体结构时曾经提到,可以在启用局部重绘模式的情况下,通过通过 <altas:UpdatePanel .../> 标签定义需要异步更新的范围。
   我们知道,传统的 HTTP 协议应用场景中,客户端在用户点击 submit 提交 form 的时候,一个 GET/POST 请求被发送到后台服务器;服务器则根据 form 的 action 指定页面,调用相应的处理者返回 HTML 格式的文本;返回结果并最终由客户端在浏览器中绘制,通常导致浏览器一次明显的刷新。
   这种模式从 Web 早期的 CGI 一直沿用到现在的 ASP.NET 中。其优点是简单易用且较为成熟,缺点则是刷新明显且速度慢。因为一个页面中可能大多数内容在此次请求中是无需改变的,而这部分冗余的内容在每次请求都会被反复传输。尤其是对一些交互性较强的页面,每个操作都沿用这个冗长的流程,响应速度和负载都是难以容忍的。期间大家也想过很多缓解方法,例如使用 iframe 等嵌入帧封装独立部件,或者在服务器端针对不同区域进行缓存等等,但因为都还是基于这个传统思路,无法从本质上解决问题。
而对遵循 AJAX 思想的 Altas 框架,则是大大迈出一步,真正实现按需出发进行重绘。
   首先,页面在定义时可以根据逻辑被分成若干个更新区域,通过 <altas:UpdatePanel .../> 标签直接定义。
   其次,Altas 将接管 ASP.NET 客户端的* Post Back 用 form,并针对局部重绘模式加入特定的参数。
   然后,Altas 将接管 ASP.NET 服务器端的页面重绘方法。如果是在局部重绘模式下,则对客户端请求进行解析,并判断需要对那些区域进行重绘。可以通过在 UpdatePanel 中指定重绘条件,来避免不必要的重绘操作。
   最后,重绘的结果会被封装成 XML 脚本,通过异步的 XMLHTTP 方式传递会客户端。客户端 Altas 引擎对返回内容进行解析后,更新到页面的相应控件上。

   整个过程完全由 Altas 自动在后台完成,不会对前台页面造成刷新或其它的影响。

   接下来我们来详细了解一下,Altas 是如何完成这一奇妙的功能。

   首先,在 ScriptManager 启用局部重绘模式后(ScriptManager.EnablePartialRendering = true),可以通过 UpdatePanel 定义任意多个更新区域,例如:

1 Atlas 实现机制浅析 [2]< atlas:UpdatePanel  runat ="server"  ID ="UpdatePanel1" >
2 Atlas 实现机制浅析 [2]     < ContentTemplate >
3 Atlas 实现机制浅析 [2]         < strong >< span  style ="text-decoration: underline" > Shipping Address </ span > : </ strong >
4 Atlas 实现机制浅析 [2]             < br  />
5 Atlas 实现机制浅析 [2]         < asp:Label  ID ="lblFirstLineShipping"  runat ="server"  Font-Bold ="False" ></ asp:Label >< br  />
6 Atlas 实现机制浅析 [2]         < asp:Label  ID ="lblSecondLineShipping"  runat ="server" ></ asp:Label >< br  />
7 Atlas 实现机制浅析 [2]         < asp:Label  ID ="lblThirdLineShipping"  runat ="server" ></ asp:Label >< br  />
8 Atlas 实现机制浅析 [2]     </ ContentTemplate >
9 Atlas 实现机制浅析 [2] </ atlas:UpdatePanel >

   更新区域的实际内容,在 ContentTemplate 属性定义。UpdatePanel.ContentTemplate 是一个 ITemplate 接口类型的属性。ASP.NET 通过此接口来定义服务端控件与其子控件的关系,定义如下:
1 Atlas 实现机制浅析 [2][ParseChildren( true ), PersistChildren( false )]
2 Atlas 实现机制浅析 [2] public   class  UpdatePanel : Control
3 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
4Atlas 实现机制浅析 [2]    [TemplateInstance(TemplateInstance.Single), PersistenceMode(PersistenceMode.InnerProperty)]
5Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]  public ITemplate ContentTemplate getset; }
6Atlas 实现机制浅析 [2]}

   而如果希望显式指定更新的触发条件,则可以通过 Triggers 属性定义,例如下列代码指定,只有在触发了 btnTrigger 按钮的 Click 事件后,才需要对 UpdatePanel2 区域进行重绘。
1 Atlas 实现机制浅析 [2]< asp:Button  runat ="server"  ID ="btnTrigger"  Text ="Trigger"  
2 Atlas 实现机制浅析 [2]  OnClick ="btnTrigger_Click"   />
3 Atlas 实现机制浅析 [2]..            
4 Atlas 实现机制浅析 [2] < atlas:UpdatePanel  runat ="server"  ID ="UpdatePanel2"  Mode ="Conditional" >
5 Atlas 实现机制浅析 [2]   < Triggers >
6 Atlas 实现机制浅析 [2]     < atlas:ControlEventTrigger  ControlID ="btnTrigger"  EventName ="Click"   />
7 Atlas 实现机制浅析 [2]   </ Triggers >
8 Atlas 实现机制浅析 [2]..
9 Atlas 实现机制浅析 [2] </ atlas:UpdatePanel >

   触发条件目前支持针对控件事件和内容的两类: ControlEventTrigger 和 ControlValueTrigger。所有触发条件都继承自 UpdatePanelTrigger 抽象类。
1 Atlas 实现机制浅析 [2]public   abstract   class  UpdatePanelTrigger
2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
3Atlas 实现机制浅析 [2]      internal UpdatePanelTrigger();
4Atlas 实现机制浅析 [2]      protected internal abstract bool HasTriggered(Control ownerControl);
5Atlas 实现机制浅析 [2]      protected internal virtual void Initialize(Control ownerControl);
6Atlas 实现机制浅析 [2]      internal void SetOwner(UpdatePanelTriggerCollection owner);
7Atlas 实现机制浅析 [2]
8Atlas 实现机制浅析 [2]      private UpdatePanelTriggerCollection _owner;
9Atlas 实现机制浅析 [2]}

   UpdatePanel 在调用 Initialize 进行初始化的时候,会调用每个 UpdatePanelTrigger 的 Initialize 方法。具体的实现可在此事件中,接管服务器框架的相应事件,或者保存服务器控件的当前值。值得注意的是,这里的通过 ControlEventTrigger.EventName 指定的是服务器端控件的事件名称,而不是 HTML 控件的事件名称。因此上述例子的按钮点击事件,名称是 Click 而不是 onclick。而在 Altas 进行服务器端局部重绘时,会询问每个 UpdatePanel 是否需要进行重绘。此时被检查的 UpdatePanel.RequiresUpdate 属性,实际上会调用每个 UpdatePanelTrigger 的 HasTriggered 方法,判断是否需要对此 UpdatePanel 进行重绘。伪代码如下:
 1 Atlas 实现机制浅析 [2]public   class  UpdatePanel : Control
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    protected internal virtual void Initialize()
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 5Atlas 实现机制浅析 [2]    if (_triggers != null)
 6Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 7Atlas 实现机制浅析 [2]      if (ScriptManager.GetCurrent(Page).IsInPartialRenderingMode)
 8Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      {
 9Atlas 实现机制浅析 [2]        _triggers.Initialize(this);
10Atlas 实现机制浅析 [2]      }

11Atlas 实现机制浅析 [2]    }

12Atlas 实现机制浅析 [2]    }

13Atlas 实现机制浅析 [2]}

14 Atlas 实现机制浅析 [2] public   sealed   class  UpdatePanelTriggerCollection : Collection < UpdatePanelTrigger >
15 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
16Atlas 实现机制浅析 [2]    internal void Initialize(Control ownerControl)
17Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
18Atlas 实现机制浅析 [2]        foreach(UpdatePanelTrigger trigger in this)
19Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        {
20Atlas 实现机制浅析 [2]            trigger.Initialize(ownerControl);
21Atlas 实现机制浅析 [2]        }
 
22Atlas 实现机制浅析 [2]    }

23Atlas 实现机制浅析 [2]}

   UpdatePanel.RequiresUpdate 判断是否需要重绘的代码与之基本类似。

   而在 UpdatePanel.OnInit 事件中,则负责在局部重绘模式时,调用 ScriptManager.RegisterUpdatePanel 方法将自己注册到管理器中。然后注册 Page.InitComplete 事件,在 UpdatePanel.OnPageInitComplete 事件处理函数中,初始化自身。伪代码如下:
 1 Atlas 实现机制浅析 [2]public   class  UpdatePanel : Control
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    protected override void OnInit(EventArgs e)
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 5Atlas 实现机制浅析 [2]        if (!DesignMode)
 6Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        {
 7Atlas 实现机制浅析 [2]            // 如果没有指定 UpdatePanel 则抛出异常
 8Atlas 实现机制浅析 [2]            if (string.IsNullOrEmpty(ID))
 9Atlas 实现机制浅析 [2]                throw new InvalidOperationException("UpdatePanel controls must have an explicit ID.");
10Atlas 实现机制浅析 [2]            
11Atlas 实现机制浅析 [2]            // 如果没有找到 ScriptManager 也抛出异常
12Atlas 实现机制浅析 [2]          ScriptManager manager = ScriptManager.GetCurrent(this.Page);
13Atlas 实现机制浅析 [2]          
14Atlas 实现机制浅析 [2]          if (manager == null)
15Atlas 实现机制浅析 [2]              throw new InvalidOperationException("An UpdatePanel requires a ScriptManager on the pageAtlas 实现机制浅析 [2]");
16Atlas 实现机制浅析 [2]              
17Atlas 实现机制浅析 [2]          // 如果启用局部重绘模式,则将自己注册到管理器
18Atlas 实现机制浅析 [2]            if (manager.IsInPartialRenderingMode)
19Atlas 实现机制浅析 [2]          manager.RegisterUpdatePanel(this);
20Atlas 实现机制浅析 [2]
21Atlas 实现机制浅析 [2]            // 页面初始化完成时对自身进行初始化
22Atlas 实现机制浅析 [2]            Page.InitComplete += new EventHandler(OnPageInitComplete);
23Atlas 实现机制浅析 [2]    
24Atlas 实现机制浅析 [2]            // 处理模板控件相关事宜
25Atlas 实现机制浅析 [2]            // Atlas 实现机制浅析 [2]
26Atlas 实现机制浅析 [2]        }

27Atlas 实现机制浅析 [2]    }

28Atlas 实现机制浅析 [2] 
29Atlas 实现机制浅析 [2]    private void OnPageInitComplete(object sender, EventArgs e)
30Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
31Atlas 实现机制浅析 [2]        // 仅在第一次初始化页面时对 UpdatePanel 进行初始化
32Atlas 实现机制浅析 [2]      if (!Page.IsPostBack)    
33Atlas 实现机制浅析 [2]      if (ScriptManager.GetCurrent(this.Page).EnablePartialRendering)
34Atlas 实现机制浅析 [2]                Initialize();
35Atlas 实现机制浅析 [2]                
36Atlas 实现机制浅析 [2]    _initialized = true;
37Atlas 实现机制浅析 [2]  }

38Atlas 实现机制浅析 [2]}

   最后,如果 UpdatePanel 需要进行完整重绘时,Page 会调用 UpdatePanel 从 Web.UI.Control 重载来的 void Render(HtmlTextWriter writer) 和 void RenderChildren(HtmlTextWriter writer) 方法进行绘制。后者会根据是否启用重绘模式,用一个 <span/> 标签将 ContentTemplate 中的子内容保护起来,用户在最终更新内容时定位。

   了解了 UpdatePanel 的使用和实现后,我们回过头来看看 ScriptManager 是如何使用它们的。

   在上一节我们曾提到,ScriptManager 在 OnPagePreRenderComplete 事件中,根据当前状态决定是否写入局部重绘模式的初始化脚本。
 1 Atlas 实现机制浅析 [2]private   void  OnPagePreRenderComplete( object  sender, EventArgs e)
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    // Atlas 实现机制浅析 [2]
 4Atlas 实现机制浅析 [2]    
 5Atlas 实现机制浅析 [2]    if (存在任意一种脚本服务、控件或引用)
 6Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 7Atlas 实现机制浅析 [2]        // Atlas 实现机制浅析 [2]
 8Atlas 实现机制浅析 [2]        
 9Atlas 实现机制浅析 [2]        if (proxyScript != null || _enablePartialRendering)
10Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        {
11Atlas 实现机制浅析 [2]            writer.Write("<script type=\"text/javascript\">");
12Atlas 实现机制浅析 [2]            
13Atlas 实现机制浅析 [2]            // Atlas 实现机制浅析 [2]
14Atlas 实现机制浅析 [2]                
15Atlas 实现机制浅析 [2]            // 输出局部重绘模式初始化脚本
16Atlas 实现机制浅析 [2]            writer.WriteLine("Web.WebForms._PageRequest._setupAsyncPostBacks(document.getElementById('" + _page.Form.ClientID + "'), '" + UniqueID + "');");
17Atlas 实现机制浅析 [2]
18Atlas 实现机制浅析 [2]            writer.Write("</script>");
19Atlas 实现机制浅析 [2]        }

20Atlas 实现机制浅析 [2]
21Atlas 实现机制浅析 [2]        // Atlas 实现机制浅析 [2]          
22Atlas 实现机制浅析 [2]    }

23Atlas 实现机制浅析 [2]}

   _setupAsyncPostBacks(...) 函数调用会在客户端载入页面时,完成 Altas 局部重绘引擎的初始化设置工作。
 1 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    this._setupAsyncPostBacks = function(form, scriptManagerID, updatePanelIDs, asyncPostbackControlIDs) 
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {        
 5Atlas 实现机制浅析 [2]        // 在 _PageRequest 对象中保存参数
 6Atlas 实现机制浅析 [2]    _form = form;
 7Atlas 实现机制浅析 [2]    _scriptManagerID = scriptManagerID;
 8Atlas 实现机制浅析 [2]    _updatePanelIDs = updatePanelIDs;
 9Atlas 实现机制浅析 [2]    _asyncPostbackControlIDs = asyncPostbackControlIDs;
10Atlas 实现机制浅析 [2]
11Atlas 实现机制浅析 [2]    form._initialAction = form.action;
12Atlas 实现机制浅析 [2]    
13Atlas 实现机制浅析 [2]    _onsubmit = form.onsubmit;
14Atlas 实现机制浅析 [2]    
15Atlas 实现机制浅析 [2]    // 接管* ASP.NET 的 form 之 onsubmit/onclick 方法
16Atlas 实现机制浅析 [2]    form.onsubmit = null;
17Atlas 实现机制浅析 [2]    form.attachEvent('onsubmit', Function.createDelegate(thisthis._onFormSubmit));
18Atlas 实现机制浅析 [2]    form.attachEvent('onclick', Function.createDelegate(thisthis._onFormElementClick));
19Atlas 实现机制浅析 [2]    
20Atlas 实现机制浅析 [2]    // 接管 ASP.NET 处理 Post Back 请求的函数
21Atlas 实现机制浅析 [2]    _originalDoPostBack = window.__doPostBack;
22Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    if (_originalDoPostBack) {
23Atlas 实现机制浅析 [2]        window.__doPostBack = Function.createDelegate(thisthis._doPostBack);
24Atlas 实现机制浅析 [2]    }

25Atlas 实现机制浅析 [2]  }

26Atlas 实现机制浅析 [2]}

   一般说来,ASP.NET 会在定义的 <form id="form1" runat="server"> 附近,增加一些处理 Post Back 的客户端代码,例如:
 1 Atlas 实现机制浅析 [2]< body >
 2 Atlas 实现机制浅析 [2]     < form  name ="aspnetForm"  method ="post"  action ="MyLists.aspx"  id ="aspnetForm" >
 3 Atlas 实现机制浅析 [2] < div >
 4 Atlas 实现机制浅析 [2] < input  type ="hidden"  name ="__EVENTTARGET"  id ="__EVENTTARGET"  value =""   />
 5 Atlas 实现机制浅析 [2] < input  type ="hidden"  name ="__EVENTARGUMENT"  id ="__EVENTARGUMENT"  value =""   />
 6 Atlas 实现机制浅析 [2] < input  type ="hidden"  name ="__LASTFOCUS"  id ="__LASTFOCUS"  value =""   />
 7 Atlas 实现机制浅析 [2] < input  type ="hidden"  name ="__VIEWSTATE"  id ="__VIEWSTATE"  value ="TCJEqyt9uS7OFuMId6rlbgLv+36H71Efw5hFAgjKyJ42XauLO8blWV/ofWtkx9Pg+SZ76WA7NvDr+/KDLacJvcKBot564ONmv4RYIXk+6GzGtINC2f4d7VDQPQXyRXwxIavJZsBZGQUwabITF0mTGs9Cus01SoG/cg2ACWQa/uofvZfU1ocGCnmKuu1SLVs6u9Y/UMOMC6lNVJgWOv3CILth90llrrIPN7nCVJC4Xyq3+nSZhzoN0/Oo4Xz4JMjUBFsy7KyDPXEaDHQGQXyRuA=="   />
 8 Atlas 实现机制浅析 [2] </ div >
 9 Atlas 实现机制浅析 [2]
10 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] < script  type ="text/javascript" >
11Atlas 实现机制浅析 [2]<!--
12Atlas 实现机制浅析 [2]var theForm = document.forms['aspnetForm'];
13Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]if (!theForm) {
14Atlas 实现机制浅析 [2]    theForm = document.aspnetForm;
15Atlas 实现机制浅析 [2]}

16Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]function __doPostBack(eventTarget, eventArgument) {
17Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
18Atlas 实现机制浅析 [2]        theForm.__EVENTTARGET.value = eventTarget;
19Atlas 实现机制浅析 [2]        theForm.__EVENTARGUMENT.value = eventArgument;
20Atlas 实现机制浅析 [2]        theForm.submit();
21Atlas 实现机制浅析 [2]    }

22Atlas 实现机制浅析 [2]}

23Atlas 实现机制浅析 [2]// -->
24Atlas 实现机制浅析 [2]
</ script >

   Altas 则通过接管上述几个客户端事件,在 ASP.NET 客户端脚本和服务端实现之间,增加了一个透明的代理层。

   其中 _onFormSubmit 事件负责完成实际的局部重绘参数构建;_onFormElementClick 事件负责保存表单点击的额外信息,并传递回服务端;_doPostBack 事件则将自动的同步页面 Post Back 操作,重定向到异步的 _onFormSubmit 操作。

   首先, _onFormSubmit 事件会针对各种状态进行判断
 1 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]Function.createDelegate  =   function (instance, method)  {
 2Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    return function() {
 3Atlas 实现机制浅析 [2]        method.apply(instance, arguments);
 4Atlas 实现机制浅析 [2]    }

 5Atlas 实现机制浅析 [2]}

 6 Atlas 实现机制浅析 [2]
 7 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
 8 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 9Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    this.get_inPostBack = function() {
10Atlas 实现机制浅析 [2]      return _request != null;
11Atlas 实现机制浅析 [2]    }

12Atlas 实现机制浅析 [2]
13Atlas 实现机制浅析 [2]    this._onFormSubmit = function() 
14Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
15Atlas 实现机制浅析 [2]        // 如果已经是 Post Back 模式,则直接返回不重复提交
16Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (this.get_inPostBack()) {
17Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]            if (window.event) {
18Atlas 实现机制浅析 [2]            window.event.returnValue = false;
19Atlas 实现机制浅析 [2]        }

20Atlas 实现机制浅析 [2]        return false;
21Atlas 实现机制浅析 [2]      }

22Atlas 实现机制浅析 [2]      
23Atlas 实现机制浅析 [2]      // 如果 form 有 onsubmit 事件处理函数,则对其进行包装
24Atlas 实现机制浅析 [2]      var continueSubmit = true;
25Atlas 实现机制浅析 [2]      
26Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (_onsubmit) {
27Atlas 实现机制浅析 [2]        continueSubmit = Function.createDelegate(this, _onsubmit);
28Atlas 实现机制浅析 [2]      }

29Atlas 实现机制浅析 [2]      
30Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (!continueSubmit) {
31Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        if (window.event) {
32Atlas 实现机制浅析 [2]          window.event.returnValue = false;
33Atlas 实现机制浅析 [2]        }

34Atlas 实现机制浅析 [2]        return false;
35Atlas 实现机制浅析 [2]      }

36Atlas 实现机制浅析 [2]      
37Atlas 实现机制浅析 [2]      // 如果表单的 action 和初始化时不同,则跳过数据处理
38Atlas 实现机制浅析 [2]      var form = _form;
39Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (form.action != form._initialAction) {
40Atlas 实现机制浅析 [2]        return true;
41Atlas 实现机制浅析 [2]      }

42Atlas 实现机制浅析 [2]    
43Atlas 实现机制浅析 [2]        // 如果不启用异步的 post back 模式,则跳过数据处理
44Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (!_postbackSettings.async) {
45Atlas 实现机制浅析 [2]          return true;
46Atlas 实现机制浅析 [2]      }

47Atlas 实现机制浅析 [2]      
48Atlas 实现机制浅析 [2]      // 数据处理
49Atlas 实现机制浅析 [2]      // Atlas 实现机制浅析 [2]
50Atlas 实现机制浅析 [2]    }

51Atlas 实现机制浅析 [2]}

   然后,_onFormSubmit 事件会根据表单中每一个包含数据的元素,构建一个完整的请求参数表。
 1 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    this._onFormSubmit = function() 
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 5Atlas 实现机制浅析 [2]        // 针对各种状态进行判断
 6Atlas 实现机制浅析 [2]        // Atlas 实现机制浅析 [2]
 7Atlas 实现机制浅析 [2]        
 8Atlas 实现机制浅析 [2]        // 建立 StringBuilder 用于构建请求内容
 9Atlas 实现机制浅析 [2]        var formBody = new Web.StringBuilder();
10Atlas 实现机制浅析 [2]        formBody.append(_scriptManagerID + '=+ _postbackSettings.panelID + '&');
11Atlas 实现机制浅析 [2]    
12Atlas 实现机制浅析 [2]        for (遍历表单中每个元素)
13Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        {
14Atlas 实现机制浅析 [2]            // 处理 INPUT、SELECT 和 TEXTAREA 三类标记
15Atlas 实现机制浅析 [2]            // 将其 id 和 value,拼接成 id=value&id=value&id=value 类型的数据
16Atlas 实现机制浅析 [2]        }

17Atlas 实现机制浅析 [2]        
18Atlas 实现机制浅析 [2]        // 如果有额外的输入信息,也添加到请求内容中,用户记录事件等信息
19Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (_additionalInput) {
20Atlas 实现机制浅析 [2]        formBody.append(_additionalInput);
21Atlas 实现机制浅析 [2]        _additionalInput = null;
22Atlas 实现机制浅析 [2]      }

23Atlas 实现机制浅析 [2]      
24Atlas 实现机制浅析 [2]      // 通过 XMLHTTP 异步发送请求
25Atlas 实现机制浅析 [2]      // Atlas 实现机制浅析 [2]
26Atlas 实现机制浅析 [2]    }

27Atlas 实现机制浅析 [2]}

   最后,_onFormSubmit 将构造得到的请求内容,通过 XMLHTTP 的方式发送到服务端。
 1 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    this._onFormSubmit = function() 
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 5Atlas 实现机制浅析 [2]        // 针对各种状态进行判断
 6Atlas 实现机制浅析 [2]        // Atlas 实现机制浅析 [2]
 7Atlas 实现机制浅析 [2]        
 8Atlas 实现机制浅析 [2]        // 根据表单中每一个包含数据的元素,构建一个完整的请求参数表
 9Atlas 实现机制浅析 [2]        // Atlas 实现机制浅析 [2]
10Atlas 实现机制浅析 [2]        
11Atlas 实现机制浅析 [2]        // 构建 XMLHTTP 封装类 WebRequest 实例
12Atlas 实现机制浅析 [2]      var request = new Web.Net.WebRequest();
13Atlas 实现机制浅析 [2]      
14Atlas 实现机制浅析 [2]      // 填充基本请求信息,delta=true 表示启用局部重绘模式,并且关闭缓存
15Atlas 实现机制浅析 [2]      request.set_url(form.action);
16Atlas 实现机制浅析 [2]      request.get_headers()['delta'] = 'true';
17Atlas 实现机制浅析 [2]      request.get_headers()['Cache-Control'] = 'no-cache';
18Atlas 实现机制浅析 [2]      request.set_timeoutInterval(90000);
19Atlas 实现机制浅析 [2]      
20Atlas 实现机制浅析 [2]      // 接管请求完成或超时的事件
21Atlas 实现机制浅析 [2]      request.completed.add(Function.createDelegate(thisthis._onFormSubmitCompleted));
22Atlas 实现机制浅析 [2]      request.timeout.add(Function.createDelegate(thisthis._onFormSubmitTimeout));
23Atlas 实现机制浅析 [2]      
24Atlas 实现机制浅析 [2]      // 提交构造得到的请求参数表
25Atlas 实现机制浅析 [2]      request.set_body(formBody.toString());
26Atlas 实现机制浅析 [2]      
27Atlas 实现机制浅析 [2]      // 进入 post back 请求状态
28Atlas 实现机制浅析 [2]      _request = request;
29Atlas 实现机制浅析 [2]      this.raisePropertyChanged('inPostBack');
30Atlas 实现机制浅析 [2]      request.invoke();
31Atlas 实现机制浅析 [2]      
32Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (window.event) {
33Atlas 实现机制浅析 [2]          window.event.returnValue = false;
34Atlas 实现机制浅析 [2]      }

35Atlas 实现机制浅析 [2]      return false;
36Atlas 实现机制浅析 [2]    }

37Atlas 实现机制浅析 [2]}

   当后台异步请求完成时,Altas 脚本会对返回结果进行解析并更新页面。这部分的讨论等完成服务端的结果讨论后再详细展开。
   对异步请求超时的情况,仅仅是终止 post back 状态,因为信息不足以判断如何进行处理。个人觉得这种处理思路过于草率了,至少应该提供一些信息,让使用者能通过 inPostBack 属性变化事件,了解到请求到底是成功还是超时。
1 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
3Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    this._onFormSubmitTimeout = function(sender, eventArgs) {
4Atlas 实现机制浅析 [2]        _request = null;
5Atlas 实现机制浅析 [2]        this.raisePropertyChanged('inPostBack');
6Atlas 实现机制浅析 [2]    }

7Atlas 实现机制浅析 [2]}
    

   _doPostBack 事件基本上就是 _onFormSubmit 的封装。它会根据 post back 请求事件的来源,判断是否需要启用异步 post back 模式。
 1 Atlas 实现机制浅析 [2]Web.WebForms._PageRequestManager  =   function () 
 2 Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2] {
 3Atlas 实现机制浅析 [2]    this._doPostBack = function(eventTarget, eventArgument) 
 4Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    {
 5Atlas 实现机制浅析 [2]      _additionalInput = null;
 6Atlas 实现机制浅析 [2]
 7Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]      if (this.get_inPostBack()) {
 8Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]        if (window.event) {
 9Atlas 实现机制浅析 [2]          window.event.returnValue = false;
10Atlas 实现机制浅析 [2]      }

11Atlas 实现机制浅析 [2]      return;
12Atlas 实现机制浅析 [2]    }

13Atlas 实现机制浅析 [2]
14Atlas 实现机制浅析 [2]        // 根据事件来源,判断是否需要启用异步模式
15Atlas 实现机制浅析 [2]    _postbackSettings = null;
16Atlas 实现机制浅析 [2]    
17Atlas 实现机制浅析 [2]    var postbackElement = findNearestElement(eventTarget);
18Atlas 实现机制浅析 [2]    
19Atlas 实现机制浅析 [2]    if (postbackElement) 
20Atlas 实现机制浅析 [2]        _postbackSettings = getPostbackSettings(postbackElement);      
21Atlas 实现机制浅析 [2]    else 
22Atlas 实现机制浅析 [2]      _postbackSettings = createPostbackSettings(true, _scriptManagerID);
23Atlas 实现机制浅析 [2]      
24Atlas 实现机制浅析 [2]    // 对同步模式,直接调用 ASP.NET 的 doPostBack 实现
25Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    if (!_postbackSettings.async) {
26Atlas 实现机制浅析 [2]        _originalDoPostBack(eventTarget, eventArgument);
27Atlas 实现机制浅析 [2]      return;
28Atlas 实现机制浅析 [2]    }

29Atlas 实现机制浅析 [2]
30Atlas 实现机制浅析 [2]        // 对异步模式,填充事件信息,并调用 _onFormSubmit 完成数据准备和提交操作
31Atlas 实现机制浅析 [2]    var form = _form;
32Atlas 实现机制浅析 [2]    form.__EVENTTARGET.value = eventTarget;
33Atlas 实现机制浅析 [2]    form.__EVENTARGUMENT.value = eventArgument;
34Atlas 实现机制浅析 [2]    this._onFormSubmit();
35Atlas 实现机制浅析 [2]    
36Atlas 实现机制浅析 [2]Atlas 实现机制浅析 [2]    if (window.event) {
37Atlas 实现机制浅析 [2]      window.event.returnValue = false;
38Atlas 实现机制浅析 [2]    }

39Atlas 实现机制浅析 [2]  }

40Atlas 实现机制浅析 [2]}

   至此,我们基本上完成了对局部重绘模式下,从 UpdatePanel 到客户端数据提交的分析。下一节将继续针对局部重绘模式,分析服务端对此模式下刷新并返回数据实现,以及客户端如何对返回数据进行解析,并更新到最终页面的控件。