vue.js合作做网站么,专业团队照片,福田网站设计方案,淄博网站制作形象http://www.cnblogs.com/joeliu/category/143125.htmlPage是WebForm编程基本元素#xff0c;它从TemplateControl派生#xff0c;而TemplateControl又从Control派生#xff0c;所以Page实际就是一个Control。同时Page也实现了IHttpHandler接口#xff0c;所以它可以接受Htt…http://www.cnblogs.com/joeliu/category/143125.html Page是WebForm编程基本元素它从TemplateControl派生而TemplateControl又从Control派生所以Page实际就是一个Control。同时Page也实现了IHttpHandler接口所以它可以接受Http请求进行处理。 可以认为一个Page是由很多的Control按照树形结构组织的而树的根就是Page一个实现了IHttphandler的Control), 整个Control树的生命周期开始于一个Http请求而终止于请求处理的结束。事实上在Http请求传入到当前的Page的时候之前已经经过了漫长的路程如果对于整个Http请求的细节感兴趣可以查看MSDN中关于应用程序的生命周期。另外关于页面的生存周期也有很多的文章可以参考比如MSDN中ASP.NET 页生命周期概述。 我这里主要讲讲我个人的理解如果有什么不妥的地方欢迎大家指正。 Page存在的目的就是对于用户的内容进行呈现它是一个IHttpHandler它实现了对HttpRequest的处理这个处理的结果就是根据请求Render出它自己而Render的内容就是HtmlCSSJavascript这些东西最终成为表现Page样子的一砖一瓦。如果做一个最简单的实现大概就是public class Page : IHttpHandler{ public void ProcessRequest(HttpContext httpContext) { Render(); }} 事实并非如此如果这样的话我们岂不是对于每个Page都要从零开始做一套完整的Render画法啊那样的Render方法将是一个很长很长的调用为了支持不同的浏览器为了应付复杂的业务逻辑里面的代码将是魔鬼也许写完一次没有人愿意维护了而且代码的复用性也很低。那么怎么办呢.net为了解决这个问题提供的是Control模型对于一个页面页面本身是一个可以呈现自己的Control同事页面里面也可以任意嵌套其它的Control每个Control都具有呈现自己的能力那样Control将具有很好的复用性和可维护性任何一个开发人员可以任意组合来自于第三方的Control来构建自己的Page。所以就需要有一个Control的类而且Page是Control的一个派生类。Page的Render方法需要递归调用RenderChildren这样让整个Control树一层一层的呈现最后得到整个Page的样子。 我们知道Http请求里面有Get和Post对于Get往往是请求一个全新的页面对于Post更多的是客户端的一个响应。对于Get的请求我们可以从零开始Render一个新的Page给客户端。但是对于Post我们一般需要让页面恢复到客户端看到的状态然后再出来Post的数据。正是由于这个原因Page在ProcessRequest的过程中不得不区分Page.IsPost or not。而如何进行场景恢复呢这大概就是ViewState产生的真正原因了ViewState是Control上的一个存储结构。它负责保存Control的一些状态。这些状态通常会被序列化到客户端的页面上当客户端的页面发出Post请求的时候.net生产的脚本会自动收集这些ViewState数据然后一起Post给服务器端。这样Page就可以加载这些状态进行场景恢复然后在恢复好的场景下出来PostData。所以在ProcessRequest里面需要加入对于LoadViewStateSaveViewStateProcessPostData的处理。 但是是否所有对于Control的设置都会序列化成ViewState呢那样不是很影响性能吗如果说我们每次在请求处理的开始阶段无论是Post还是非Post)都用代码初始化Control不是就不需要利用ViewState加载状态了啊所以在ProcessRequest里面又有了新的过程的加入Init在Init里面可以设置Control的一些属性和状态而在Init以后才通过TrackViewState来通知ControlTrackViewState阶段后对Control的修改才会SaveViewState的时候保存下来否则都不保存。 类似的例子还有很多就像我们自己做的软件产品很多时候第一个版本都是简单的以后随着需求的增加代码越来越多结构越来越复杂也许未来版本的Page还会有更多的变化总之经过很多的需求Page对于Request的处理就变得复杂了最后就分为下面的几个阶段关于这些阶段的介绍我们可以在Google上搜索很多的文章我认为我们不仅仅要了解这些阶段还要深入理解否则想做出好的Control是很困难的。代码中的数字列出了主要的页面生命周期的阶段对于PostBack和CallBack阶段会发生一些变化也加了说明private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint) { // 1. PreInit this.PerformPreInit(); // 2. Init this.InitRecursive(null); this.OnInitComplete(EventArgs.Empty); // 对于Postback,插入下面处理 if (this.IsPostBack) { // 加载ViewState和ControlState进行场景恢复 this.LoadAllState(); // 第一次处理PostData this.ProcessPostData(this._requestValueCollection, true); } // 3. PreLoad this.OnPreLoad(EventArgs.Empty); // 4. Load this.LoadRecursive(); // 对于Postback插入下面处理 if (this.IsPostBack) { // 第二次处理PostData this.ProcessPostData(this._leftoverPostData, false); // 如果PostData表面某个Control数据发生变化那么RaisePostDataChanged事件 this.RaiseChangedEvents(); // RaisePostBackEvent this.RaisePostBackEvent(this._requestValueCollection); } this.OnLoadComplete(EventArgs.Empty); // 对于CallBackRaiseCallBackEvent if (this.IsPostBack this.IsCallback) { this.PrepareCallback(callbackControlID); } else if (!this.IsCrossPagePostBack) { // 5. PreRender this.PreRenderRecursiveInternal(); } // 对于CallBack, Render出CallBack的结果 if (this.IsCallback) { this.RenderCallback(); } else if (!this.IsCrossPagePostBack) { this.PerformPreRenderComplete(); // 6. SaveViewStae和ControlState this.SaveAllState(); this.OnSaveStateComplete(EventArgs.Empty); // 7. Render 整个Control this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output)); } } 1. PreInit 阶段 这个阶段是Page独有的在Control上是没有的这个阶段主要是.net Framework自己在里面做了一些自己的初始化工作比如Skin的加载MasterPage的加载。会发Page.OnPreInit事件源代码如下private void PerformPreInit(){ this.OnPreInit(EventArgs.Empty); this.InitializeThemes(); this.ApplyMasterPage(); this._preInitWorkComplete true;} 2. Init阶段 InitRecursive是Page从Control继承的方法它主要进行Control的一些初始化和标记工作 a. 对当前Control进行准确初始化包括初始化_adapter;ApplySkin(this.Page);设置标记this._controlState ControlState.Initialized;TrackViewState//开始跟踪变化这个阶段以后的变化会存入ViewState b. 对子Control进行初始化初始化nameContainer属性初始化page属性自动生成Id递归调用子Control的InitRecursive方法 有个值得注意的是如果在Control树执行完Init之后创建一个新的Control加入到树上那么当它加入的时候在父Control的AddedControl方法里面如果发现已经Initialized那么手动调用新加入Control的InitRecursive方法。 所以我们Control的Init阶段给Control的一些需要查找才可以得到的属性进行直接赋值如PagenameContainer这样可以提高这些属性的访问速度。 3. PreLoad阶段 仅仅发Page独有的事件OnPreLoad事件 4. Load阶段 LoadRecursive是Page从Control继承的方法它比较简单仅仅是递归调用子Control的LoadRecursive方法然后做一个阶段标记 this._controlState ControlState.Loaded; 5. PreRender阶段 PreRenderRecursiveInternal是Page从Control继承的方法这个方法会 EnsureChildControls--调用CreateChildControls确保子Control创建完毕为接下来的Render做准备递归调用子Control的PreRenderRecursiveInternal 6. SaveAllState 阶段 主要存储ControlState和ViewStateControlState和ViewState唯一不同的地方在于ControlState是不可以禁用的而ViewState可以禁用事实上.net Framework在ControlState里面还加入了一个数据这个数据是一个ArrayList里面存入了所有的需要处理PostData的Control的Id这样在Post阶段.net Framework会根据ArrayList里面保存的Control来依次调用ProcessPostData方法前提是这些Control最好实现IPostDataHandler接口。 7. Render阶段 RenderControl是Page从Control继承的方法这个方法会递归调用子Control的RenderControl ()这样一层一层进行呈现。 总结 InitLoadPreRenderSaveStateRender这几个阶段会在整个Control树上递归贯穿。在Init里面对Control的修改一般是不会保存到ViewState里面这个阶段以后的变化会存入ViewState。 LoadAllState发生在Init和Load之间因为LoadState会进行场景恢复所以如果我们在Page_Load里面进行了一些初始化工作那么如果在Post阶段就不需要二次初始化了所以经常会写这样的代码 if (Page.IsPostBack) {...; // Init Controls},真正的原因就在这里了。 另外也有一些在Load事件里面动态创建Control的做法这个时候也要小心了。因为LoadAllState只会加载ViewState数据包并不会创建Control人家也不知道你的Control什么类型啊所以无论是否IsPostBackControl都需要创建并且加入到Controls集合。如果在Post阶段当Control一加入集合就会被调用InitRecursive方法进行初始化同时还会把父Control上保存的该Control的ViewState传给它让它加载。关于加载ViewState的知识也比较复杂有安装Control Index加载和安装Control Id加载两种细节可以在以后专题讲述。 补充关于一个Control的生和死 Control的生可以分为两种一种是在DesignMode下设计好一旦一个请求到来Page被创建这个时候Control就已经添加到以Page为根的Control树了所以它可以经历完整的页面生命周期Init Load。。。另一种是在页面生命周期的某个阶段创建例如Init的时候或者Load的时候这个时候.net为了继续保持Control能经历页面的整个生命周期会在它被加入到Control树的瞬间进行一些补充式的调用具体实现可以看下面的Control.AddedControl方法。 protected internal virtual void AddedControl(Control control, int index){ // 1. 初始化PageParentNameContainer,ID control._parent this; control._page this.Page; control.flags.Clear(0x20000); Control namingContainer this.flags[0x80] ? this : this._namingContainer; if (namingContainer ! null) { control.UpdateNamingContainer(namingContainer); if ((control._id null) !control.flags[0x40]) { control.GenerateAutomaticID(); } else if ((control._id ! null) || ((control._occasionalFields ! null) (control._occasionalFields.Controls ! null))) { namingContainer.DirtyNameTable(); } } // 2. 判断当前Control所在的页面生命周期阶段然后对于新加入的Control进行补充调用 if (this._controlState ControlState.ChildrenInitialized) { control.InitRecursive(namingContainer); if (((control._controlState ControlState.Initialized) (control.RareFields ! null)) control.RareFields.RequiredControlState) { this.Page.RegisterRequiresControlState(control); } if (this._controlState ControlState.ViewStateLoaded) { object savedState null; if ((this._occasionalFields ! null) (this._occasionalFields.ControlsViewState ! null)) { savedState this._occasionalFields.ControlsViewState[index]; if (this.LoadViewStateByID) { control.EnsureID(); savedState this._occasionalFields.ControlsViewState[control.ID]; this._occasionalFields.ControlsViewState.Remove(control.ID); } else { savedState this._occasionalFields.ControlsViewState[index]; this._occasionalFields.ControlsViewState.Remove(index); } } control.LoadViewStateRecursive(savedState); if (this._controlState ControlState.Loaded) { control.LoadRecursive(); if (this._controlState ControlState.PreRendered) { control.PreRenderRecursiveInternal(); } } } }} 同样Control的死也可以分为两种一种就是完整的经历一个页面请求.net会在所有的请求都处理完了之后也就是在我上面讲的所有的阶段之后调用一个ProcessRequestClearUp()方法另外一种就是在页面的生命周期的某个阶段调用Controls.Remove(control)方法来干掉Control在这个调用发生后父Control有一个叫做RemovedControl的方法会调用和上面的AddedControl是兄弟哦来进行清理工作其实现基本是上面AddedControl的反操作。 值得注意的是无论是RemovedControl还是ProcessRequestClearUp它们都在Control还没有从Control树上摘掉的时候调用了一个非常重要的方法control.UnloadRecursive(),这个方法从最底层的子Control向上直到当前正在移除的Control依次执行OnUnload方法所以做WebControl的时候我们可以override on_Unload()方法在这个方法里面可以摘除Event摘除与Control树关联的变量做一些清理工作。这点是非常有用的。 后记从来没有往首页上发布过我的帖子。当我昨天发布了前言后发现很多人对这个话题都很感兴趣一方面感觉高兴一方面也感觉压力毕竟我没有写过什么像样的技术文章生怕辜负大家厚望。最近白天工作忙只能晚上在家好好整理思路写出来。因为对于写WebControl的基本方法已经有很多地方介绍了比如《道不远人》也没有重复一遍的必要所以我主要写写我对WebForm主要实现的理解。我认为这是我们设计一个专业的WebControl的基本功。有什么写的不清楚的地方欢迎大家指正我一定尽力补充。 转载于:https://www.cnblogs.com/limxc/archive/2008/07/22/1249070.html