|
//------------------------------------------------------------------------------
// <copyright file="MasterPage.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* MasterPage class definition
*
* Copyright (c) 1998 Microsoft Corporation
*/
namespace System.Web.UI {
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Security.Permissions;
using System.Reflection;
using System.Web.Hosting;
using System.Web.Compilation;
using System.Web.UI.WebControls;
using System.Web.Util;
public class MasterPageControlBuilder : UserControlControlBuilder {
internal static readonly String AutoTemplatePrefix = "Template_";
}
/// <devdoc>
/// Default ControlBuilder used to parse master page files. Note that this class inherits from FileLevelPageControlBuilder
/// to reuse masterpage handling code.
/// </devdoc>
public class FileLevelMasterPageControlBuilder: FileLevelPageControlBuilder {
internal override void AddContentTemplate(object obj, string templateName, ITemplate template) {
MasterPage master = (MasterPage)obj;
master.AddContentTemplate(templateName, template);
}
}
/// <devdoc>
/// <para>This class is not marked as abstract, because the VS designer
/// needs to instantiate it when opening .master files</para>
/// </devdoc>
[
Designer("Microsoft.VisualStudio.Web.WebForms.MasterPageWebFormDesigner, " + AssemblyRef.MicrosoftVisualStudioWeb, typeof(IRootDesigner)),
ControlBuilder(typeof(MasterPageControlBuilder)),
ParseChildren(false)
]
public class MasterPage : UserControl {
private VirtualPath _masterPageFile;
private MasterPage _master;
// The collection used to store the templates created on the content page.
private IDictionary _contentTemplates;
// The collection used to store the content templates defined in MasterPage.
private IDictionary _contentTemplateCollection;
private IList _contentPlaceHolders;
private bool _masterPageApplied;
// The page or masterpage that hosts this masterPage.
internal TemplateControl _ownerControl;
public MasterPage() {
}
/// <devdoc>
/// <para>Dictionary used to store the content templates that are passed in from the content pages.</para>
/// </devdoc>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal IDictionary ContentTemplates {
get {
return _contentTemplates;
}
}
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal IList ContentPlaceHolders {
get {
if (_contentPlaceHolders == null) {
_contentPlaceHolders = new ArrayList();
}
return _contentPlaceHolders;
}
}
/// <devdoc>
/// <para>The MasterPage used by this nested MasterPage control.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
WebSysDescription(SR.MasterPage_MasterPage)
]
public MasterPage Master {
get {
if (_master == null && !_masterPageApplied) {
_master = MasterPage.CreateMaster(this, Context, _masterPageFile, _contentTemplateCollection);
}
return _master;
}
}
/// <devdoc>
/// <para>Gets and sets the masterPageFile of this control.</para>
/// </devdoc>
[
DefaultValue(""),
WebCategory("Behavior"),
WebSysDescription(SR.MasterPage_MasterPageFile)
]
public string MasterPageFile {
get {
return VirtualPath.GetVirtualPathString(_masterPageFile);
}
set {
if (_masterPageApplied) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePageEvent, "MasterPageFile", "Page_PreInit"));
}
if (value != VirtualPath.GetVirtualPathString(_masterPageFile)) {
_masterPageFile = VirtualPath.CreateAllowNull(value);
if (_master != null && Controls.Contains(_master)) {
Controls.Remove(_master);
}
_master = null;
}
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal void AddContentTemplate(string templateName, ITemplate template) {
if (_contentTemplateCollection == null) {
_contentTemplateCollection = new Hashtable(10, StringComparer.OrdinalIgnoreCase);
}
try {
_contentTemplateCollection.Add(templateName, template);
}
catch (ArgumentException) {
throw new HttpException(SR.GetString(SR.MasterPage_Multiple_content, templateName));
}
}
internal static MasterPage CreateMaster(TemplateControl owner, HttpContext context,
VirtualPath masterPageFile, IDictionary contentTemplateCollection) {
Debug.Assert(owner is MasterPage || owner is Page);
MasterPage master = null;
if (masterPageFile == null) {
if (contentTemplateCollection != null && contentTemplateCollection.Count > 0) {
throw new HttpException(SR.GetString(SR.Content_only_allowed_in_content_page));
}
return null;
}
// If it's relative, make it *app* relative. Treat is as relative to this
// user control (ASURT 55513)
VirtualPath virtualPath = VirtualPathProvider.CombineVirtualPathsInternal(
owner.TemplateControlVirtualPath, masterPageFile);
// Compile the declarative control and get its Type
ITypedWebObjectFactory result = (ITypedWebObjectFactory)BuildManager.GetVPathBuildResult(
context, virtualPath);
// Make sure it has the correct base type
if (!typeof(MasterPage).IsAssignableFrom(result.InstantiatedType)) {
throw new HttpException(SR.GetString(SR.Invalid_master_base,
masterPageFile));
}
master = (MasterPage)result.CreateInstance();
master.TemplateControlVirtualPath = virtualPath;
if (owner.HasControls()) {
foreach (Control control in owner.Controls) {
LiteralControl literal = control as LiteralControl;
if (literal == null || Util.FirstNonWhiteSpaceIndex(literal.Text) >= 0) {
throw new HttpException(SR.GetString(SR.Content_allowed_in_top_level_only));
}
}
// Remove existing controls.
owner.Controls.Clear();
}
// Make sure the control collection is writable.
if (owner.Controls.IsReadOnly) {
throw new HttpException(SR.GetString(SR.MasterPage_Cannot_ApplyTo_ReadOnly_Collection));
}
if (contentTemplateCollection != null) {
foreach(String contentName in contentTemplateCollection.Keys) {
if (!master.ContentPlaceHolders.Contains(contentName.ToLower(CultureInfo.InvariantCulture))) {
throw new HttpException(SR.GetString(SR.MasterPage_doesnt_have_contentplaceholder, contentName, masterPageFile));
}
}
master._contentTemplates = contentTemplateCollection;
}
master._ownerControl = owner;
master.InitializeAsUserControl(owner.Page);
owner.Controls.Add(master);
return master;
}
internal static void ApplyMasterRecursive(MasterPage master, IList appliedMasterFilePaths) {
Debug.Assert(appliedMasterFilePaths != null);
// Recursively apply master pages to the nested masterpages.
if (master.Master != null) {
string pageFile = master._masterPageFile.VirtualPathString.ToLower(CultureInfo.InvariantCulture);
if (appliedMasterFilePaths.Contains(pageFile)) {
throw new InvalidOperationException(SR.GetString(SR.MasterPage_Circular_Master_Not_Allowed, master._masterPageFile));
}
appliedMasterFilePaths.Add(pageFile);
ApplyMasterRecursive(master.Master, appliedMasterFilePaths);
}
master._masterPageApplied = true;
}
public void InstantiateInContentPlaceHolder(Control contentPlaceHolder, ITemplate template) {
HttpContext context = HttpContext.Current;
// Remember the old TemplateControl
TemplateControl oldControl = context.TemplateControl;
// Storing the template control into the context
// since each thread needs to set it differently.
context.TemplateControl = _ownerControl;
try {
// Instantiate the template using the correct TemplateControl
template.InstantiateIn(contentPlaceHolder);
}
finally {
// Revert back to the old templateControl
context.TemplateControl = oldControl;
}
}
}
}
|