请选择 进入手机版 | 继续访问电脑版
贠老师培训群:150322713    贠老师QQ:767708506

贠老师office培训-excel学习网

 找回密码
 立即注册
点击咨询贠老师
查看: 372|回复: 6

Web开发学习心得7——MasterPage的实现原理

[复制链接]

607

主题

604

帖子

1909

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
1909
发表于 2016-1-25 23:06:44 | 显示全部楼层 |阅读模式

MasterPage是Asp.net2.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的源代码,出奇的是,竟也如此简单,以至于我也没有从该源代码中找到多少有价值的信息。 

MasterPage

[ControlBuilder(typeof(MasterPageControlBuilder)), Designer("Microsoft.VisualStudio.Web.WebForms.MasterPageWebFormDesigner, Microsoft.VisualStudio.Web, Version=8.0.0.0, 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;
            }
        }
    }
}


回复

使用道具 举报

2

主题

920

帖子

87

积分

注册会员

Rank: 2

积分
87
发表于 2016-3-8 16:33:55 | 显示全部楼层
赞一个
回复 支持 反对

使用道具 举报

1

主题

894

帖子

20

积分

注册会员

Rank: 2

积分
20
发表于 2016-3-16 21:54:49 | 显示全部楼层
希望楼主能够收集更多的资料,谢谢了!
回复 支持 反对

使用道具 举报

0

主题

879

帖子

10

积分

注册会员

Rank: 2

积分
10
发表于 2016-3-21 15:03:18 | 显示全部楼层
顶一个
回复 支持 反对

使用道具 举报

3

主题

986

帖子

67

积分

注册会员

Rank: 2

积分
67
发表于 2018-3-17 20:11:15 | 显示全部楼层
还有许多问题不明白,有点恼火啊!
回复 支持 反对

使用道具 举报

7

主题

833

帖子

65

积分

注册会员

Rank: 2

积分
65
发表于 2018-10-10 15:29:07 | 显示全部楼层
顶一个
回复 支持 反对

使用道具 举报

3

主题

986

帖子

67

积分

注册会员

Rank: 2

积分
67
发表于 2018-10-19 10:36:29 | 显示全部楼层
顶顶
回复 支持 反对

使用道具 举报

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

本版积分规则



陕ICP备15003731号  

贠老师培训 GMT+8, 2018-11-21 02:15 , Processed in 0.203757 second(s), 33 queries .

快速回复 返回顶部 返回列表