Web开发学习心得.doc_第1页
Web开发学习心得.doc_第2页
Web开发学习心得.doc_第3页
Web开发学习心得.doc_第4页
Web开发学习心得.doc_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Web开发学习心得7MasterPage的实现原理MasterPage是A2.0引入的一个非常实用的特性,怎么用,我想不用我说,基本上大家都会,这里要讲的是,它是如何实现的。 在深入源代码去探索MasterPage之前,我以为MasterPage的实现应该是比较复杂的,也一直纳闷为什么MasterPage类会继承于UserControl类,感觉这两者好像差得很远。昨天晚上,我专门抽出时间,阅读了部分与MasterPage有关的源代码,终于明白了是怎么回事,在那突然明白的那一刻,真有如醍醐灌顶,拍案叫绝,不得不佩服微软的那些guys。 下面就是我的探索之旅的过程(大家也可以跳过该部分,直接看后面的真相大白部分): 1、我首先查看的是Page.ProcessRequestMain方法,我们知道,Page类大部分特性,包括LifeCycle、PostBack、ProcessPostData等都是在该方法中实现,所以,我想,MasterPage的实现肯定在该方法中有不少的体现。然而,令我惊讶的是,我居然没有在该方法中找到任何有关MasterPage的线索,而仅仅在this.PerformPreInit()中,找到唯一一个ApplyMasterPage()方法。而该方法也出奇的简单,感觉仅仅是将递归的各级MasterPage的._masterPageApplied字段设为true而已。当时,我忽略了一个重要的东西,就是代码中对this.Master这个属性的访问,实际上,奥秘就在对这个属性的访问上(下文将叙述)。private void PerformPreInit() this.OnPreInit(EventArgs.Empty); this.InitializeThemes(); this.ApplyMasterPage(); this._preInitWorkComplete = true;Page.ApplyMasterPage()private void ApplyMasterPage() if (this.Master != null) ArrayList appliedMasterFilePaths = new ArrayList(); appliedMasterFilePaths.Add(this._masterPageFile.VirtualPathString.ToLower(CultureInfo.InvariantCulture); MasterPage.ApplyMasterRecursive(this.Master, appliedMasterFilePaths); 2、我查看了MasterPage的源代码,出奇的是,竟也如此简单,以至于我也没有从该源代码中找到多少有价值的信息。MasterPageControlBuilder(typeof(MasterPageControlBuilder), Designer(Microsoft.VisualStudio.Web.WebForms.MasterPageWebFormDesigner, Microsoft.VisualStudio.Web, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, typeof(IRootDesigner), ParseChildren(false), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)public class MasterPage : UserControl private IList _contentPlaceHolders; private IDictionary _contentTemplateCollection; private IDictionary _contentTemplates; private MasterPage _master; private bool _masterPageApplied; private VirtualPath _masterPageFile; internal TemplateControl _ownerControl; EditorBrowsable(EditorBrowsableState.Advanced) protected internal void AddContentTemplate(string templateName, ITemplate template) if (this._contentTemplateCollection = null) this._contentTemplateCollection = new Hashtable(10, StringComparer.OrdinalIgnoreCase); try this._contentTemplateCollection.Add(templateName, template); catch (ArgumentException) throw new HttpException(SR.GetString(MasterPage_Multiple_content, new object templateName ); internal static void ApplyMasterRecursive(MasterPage master, IList appliedMasterFilePaths) if (master.Master != null) string str = master._masterPageFile.VirtualPathString.ToLower(CultureInfo.InvariantCulture); if (appliedMasterFilePaths.Contains(str) throw new InvalidOperationException(SR.GetString(MasterPage_Circular_Master_Not_Allowed, new object master._masterPageFile ); appliedMasterFilePaths.Add(str); ApplyMasterRecursive(master.Master, appliedMasterFilePaths); master._masterPageApplied = true; internal static MasterPage CreateMaster(TemplateControl owner, HttpContext context, VirtualPath masterPageFile, IDictionary contentTemplateCollection) MasterPage child = null; if (masterPageFile = null) if (contentTemplateCollection != null) & (contentTemplateCollection.Count 0) throw new HttpException(SR.GetString(Content_only_allowed_in_content_page); return null; VirtualPath virtualPath = VirtualPathProvider.CombineVirtualPathsInternal(owner.TemplateControlVirtualPath, masterPageFile); ITypedWebObjectFactory vPathBuildResult = (ITypedWebObjectFactory) BuildManager.GetVPathBuildResult(context, virtualPath); if (!typeof(MasterPage).IsAssignableFrom(vPathBuildResult.InstantiatedType) throw new HttpException(SR.GetString(Invalid_master_base, new object masterPageFile ); child = (MasterPage) vPathBuildResult.CreateInstance(); child.TemplateControlVirtualPath = virtualPath; if (owner.HasControls() foreach (Control control in owner.Controls) LiteralControl control2 = control as LiteralControl; if (control2 = null) | (Util.FirstNonWhiteSpaceIndex(control2.Text) = 0) throw new HttpException(SR.GetString(Content_allowed_in_top_level_only); owner.Controls.Clear(); if (owner.Controls.IsReadOnly) throw new HttpException(SR.GetString(MasterPage_Cannot_ApplyTo_ReadOnly_Collection); if (contentTemplateCollection != null) foreach (string str in contentTemplateCollection.Keys) if (!child.ContentPlaceHolders.Contains(str.ToLower(CultureInfo.InvariantCulture) throw new HttpException(SR.GetString(MasterPage_doesnt_have_contentplaceholder, new object str, masterPageFile ); child._contentTemplates = contentTemplateCollection; child._ownerControl = owner; child.InitializeAsUserControl(owner.Page); owner.Controls.Add(child); return child; Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced) protected internal IList ContentPlaceHolders get if (this._contentPlaceHolders = null) this._contentPlaceHolders = new ArrayList(); return this._contentPlaceHolders; Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced) protected internal IDictionary ContentTemplates get return this._contentTemplates; WebSysDescription(MasterPage_MasterPage), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false) public MasterPage Master get if (this._master = null) & !this._masterPageApplied) this._master = CreateMaster(this, this.Context, this._masterPageFile, this._contentTemplateCollection); return this._master; WebSysDescription(MasterPage_MasterPageFile), WebCategory(Behavior), DefaultValue() public string MasterPageFile get return VirtualPath.GetVirtualPathString(this._masterPageFile); set if (this._masterPageApplied) throw new InvalidOperationException(SR.GetString(PropertySetBeforePageEvent, new object MasterPageFile, Page_PreInit ); if (value != VirtualPath.GetVirtualPathString(this._masterPageFile) this._masterPageFile = VirtualPath.CreateAllowNull(value); if (this._master != null) & this.Controls.Contains(this._master) this.Controls.Remove(this._master); this._master = null; 3、我又查看了ContentPlaceHolder类、Content类,心想,难道奥秘在这两个控件上?打开源代码一看,彻底晕倒,这两个类简单得简直不能让人相信,ContentPlaceHolder居然是一个空类,仅仅起到一个标识的作用,而Content居然也仅仅只有ContentPlaceHolderID唯一一个string属性。public class ContentPlaceHolder : Control, INonBindingContainer, INamingContainerContentpublic class Content : Control, INonBindingContainer, INamingContainer private string _contentPlaceHolderID; public string ContentPlaceHolderID get if (this._contentPlaceHolderID = null) return string.Empty; return this._contentPlaceHolderID; set if (!base.DesignMode) throw new NotSupportedException(SR.GetString(Property_Set_Not_Supported, new object ContentPlaceHolderID, base.GetType().ToString() ); this._contentPlaceHolderID = value; 4、此时,我几乎已经没法再从A源代码中找到其他有关MasterPage的有价值的信息了。于是,我决定写一个简单的Web应用程序,该应用程序仅仅只有一个MasterPage页与Default页,并将其编译,查看编译后的代码,看看是否能找到有价值的信息。 源代码如下:MasterPage.master Default.aspx 编译后代码如下:CompilerGlobalScopepublic class masterpage_master : MasterPage private static bool _initialized; private ITemplate _Template_ContentPlaceHolder; protected ContentPlaceHolder ContentPlaceHolder; protected HtmlForm form1; protected Button master; DebuggerNonUserCode public masterpage_master() base.AppRelativeVirtualPath = /MasterPage.master; if (!_initialized) _initialized = true; base.ContentPlaceHolders.Add(contentplaceholder); DebuggerNonUserCode private ContentPlaceHolder _BuildControlContentPlaceHolder() ContentPlaceHolder container = new ContentPlaceHolder(); this.ContentPlaceHolder = container; container.ID = ContentPlaceHolder; if (base.ContentTemplates != null) this._Template_ContentPlaceHolder = (ITemplate) base.ContentTemplatesContentPlaceHolder; if (this._Template_ContentPlaceHolder != null) this._Template_ContentPlaceHolder.InstantiateIn(container); return container; IParserAccessor accessor = container; accessor.AddParsedSubObject(new LiteralControl(rn ); Button button = this._BuildControlmaster(); accessor.AddParsedSubObject(button); accessor.AddParsedSubObject(new LiteralControl(rn ); return container; DebuggerNonUserCode private HtmlForm _BuildControlform1() HtmlForm form = new HtmlForm(); this.form1 = form; form.ID = form1; IParserAccessor accessor = form; accessor.AddParsedSubObject(new LiteralControl(rn rn ); ContentPlaceHolder holder = this._BuildControlContentPlaceHolder(); accessor.AddParsedSubObject(holder); accessor.AddParsedSubObject(new LiteralControl(rn rn ); return form; DebuggerNonUserCode private Button _BuildControlmaster() Button button = new Button(); this.master = button; button.ApplyStyleSheetSkin(this.Page); button.ID = master; button.Text = master; return button; DebuggerNonUserCode private void _BuildControlTree(masterpage_master _ctrl) IParserAccessor accessor = _ctrl; accessor.AddParsedSubObject(new LiteralControl(rnrnrnrnrnrn rnrnrn ); HtmlForm form = this._BuildControlform1(); accessor.AddParsedSubObject(form); accessor.AddParsedSubObject(new LiteralControl(rnrnrn); DebuggerNonUserCode protected override void FrameworkInitialize() base.FrameworkInitialize(); this._BuildControlTree(this); protected HttpApplication ApplicationInstance get return this.Context.ApplicationInstance; protected DefaultProfile Profile get return (DefaultProfile) this.Context.Profile; protected override bool SupportAutoEvents get return false; TemplateContainer(typeof(MasterPage), TemplateInstance(TemplateInstance.Single) public virtual ITemplate Template_ContentPlaceHolder get return this._Template_ContentPlaceHolder; set this._Template_ContentPlaceHolder = value; CodeCompilerGlobalScopepublic class default_aspx : Page, IRequiresSessionState, IHttpHandler private static object _fileDependencies; private static bool _initialized; protected Button default; DebuggerNonUserCode public default_aspx() base.AppRelativeVirtualPath = /Default.aspx; if (!_initialized) string virtualFileDependencies = new string /Default.aspx, /MasterPage.master ; _fileDependencies = base.GetWrappedFileDependencies(virtualFileDependencies); _initialized = true; base.Server.ScriptTimeout = 0x1c9c380; DebuggerNonUserCode private void _BuildControlContent(Control _ctrl) IParserAccessor accessor = _ctrl; accessor.AddParsedSubObject(new LiteralControl(rn ); Button button = this._BuildControldefault(); accessor.AddParsedSubObject(button); accessor.AddParsedSubObject(new LiteralControl(rn); DebuggerNonUserCode private Button _BuildControldefault() Button button = new Button(); this.default = button; button.TemplateControl = this; button.ApplyStyleSheetSkin(this); button.ID = default; button.Text = default; return button; DebuggerNonUserCode private void _BuildControlTree(default_aspx _ctrl) _ctrl.Title = ; _ctrl.MasterPageFile = /MasterPage.master; this.InitializeCulture(); base.AddContentTemplate(ContentPlaceHolder, new CompiledTemplateBuilder(new BuildTemplateMethod(this._BuildControlContent); IParserAccessor accessor = _ctrl; accessor.AddParsedSubObject(new LiteralControl(rnrn); DebuggerNonUserCode protected override void FrameworkInitialize() base.FrameworkInitialize(); this._BuildControlTree(this); base.AddWrappedFileDependencies(_fileDependencies); base.Request.ValidateInput(); DebuggerNonUserCode public override int GetTypeHashCode() return -2002306427; DebuggerNonUserCode public override void ProcessRequest(HttpContext context) base.ProcessRequest(context); protected HttpApplication ApplicationInstance get return this.Context.ApplicationInstance; public masterpage_master Master get return (masterpage_master) base.Master; protected DefaultProfile Profile get return (DefaultProfile) this.Context.Profile; protected override bool SupportAutoEvents get return false; 我们首先观察default_aspx的BuildControlTree方法,该方法调用了base.AddContentTemplate(ContentPlaceHolder, new CompiledTemplateBuilder(new BuildTemplateMethod(this._BuildControlContent);而该方法实质上只有一行代码,即this._contentTemplateCollection.Add(templateName, template);其中,_contentTemplateCollection是IDictionary类型。因此,base.AddContentTemplate只有一个功能,即在Page的_contentTemplateCollection中添加一个CompliedTemplateBuilder类型的对象。那么该对象有啥作用呢?为了不岔开话题,这里不对该对象做详细描述,只给出结论:该对象实现ITemplate接口,其接口方法InstantiateIn(Control container)具体实现为为container添加BuildTemplateMethod委托所创建的控件。这话有点拗口,简单地就刚才那个例子来说,就是如果你调用该对象的InstantiateIn(Control container)方法,就为该container添加this._BuildControlContent()方法所创建的控件做为子控件。 5、我们继续来看看masterpage_master的_BuildControlContentPlaceHolder()方法,我们发现,该方法即调用了刚才讨论的那个InstantiateIn方法。哈,原来在这里,终于明白了,原来Page里Content控件中的所有内容最终都将变成其对应的MasterPage中的ContentPlaceHolder的子控件。等一下,这个结论下得有点早,难道这里的base.ContentTemplates属性就等于Page的_contentTemplateCollection字段吗?如果是,那么上面的结论就是正确的。 6、我们重新回到1中的代码,查看Page.Master属性的实现,我们发现,它调用了MasterPage的CreateMaster静态方法,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论