Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / xsp / System / Web / UI / Control.cs / 7 / Control.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.UI { using System.Text; using System.ComponentModel; using System; using System.Collections; using System.Collections.Specialized; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; using System.IO; using HttpException = System.Web.HttpException; using System.Web.Configuration; using System.Web.UI.Adapters; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.Util; using System.Web.Hosting; using System.Web.Caching; using System.Security.Permissions; // Delegate used for the compiled template public delegate void RenderMethod(HtmlTextWriter output, Control container); public delegate Control BuildMethod(); // Defines the properties, methods, and events that are shared by all server // controls in the Web Forms page framework. [ Bindable(true), DefaultProperty("ID"), DesignerCategory("Code"), Designer("System.Web.UI.Design.ControlDesigner, " + AssemblyRef.SystemDesign), DesignerSerializer("Microsoft.VisualStudio.Web.WebForms.ControlCodeDomSerializer, " + AssemblyRef.MicrosoftVisualStudioWeb, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + AssemblyRef.SystemDesign), Themeable(false), ToolboxItemFilter("System.Web.UI", ToolboxItemFilterType.Require), ToolboxItemAttribute("System.Web.UI.Design.WebControlToolboxItem, " + AssemblyRef.SystemDesign) ] [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class Control : IComponent, IParserAccessor, IUrlResolutionService, IDataBindingsAccessor, IControlBuilderAccessor, IControlDesignerAccessor, IExpressionsAccessor { internal static readonly object EventDataBinding = new object(); internal static readonly object EventInit = new object(); internal static readonly object EventLoad = new object(); internal static readonly object EventUnload = new object(); internal static readonly object EventPreRender = new object(); private static readonly object EventDisposed = new object(); internal const bool EnableViewStateDefault = true; internal const char ID_SEPARATOR = '$'; private const char ID_RENDER_SEPARATOR = '_'; internal const char LEGACY_ID_SEPARATOR = ':'; private string _id; // allows us to reuse the id variable to store a calculated id w/o polluting the public getter private string _cachedUniqueID; private Control _parent; // fields related to being a container private ControlState _controlState; private StateBag _viewState; // The naming container that this control leaves in. Note that even if // this ctrl is a naming container, it will not point to itself, but to // the naming container that contains it. private Control _namingContainer; internal Page _page; private OccasionalFields _occasionalFields; private TemplateControl _templateControl; // The virtual directory of the Page or UserControl that hosts this control. private VirtualPath _templateSourceVirtualDirectory; internal ControlAdapter _adapter; // const masks into the BitVector32 private const int idNotCalculated = 0x00000001; private const int marked = 0x00000002; private const int disableViewState = 0x00000004; private const int controlsCreated = 0x00000008; private const int invisible = 0x00000010; private const int visibleDirty = 0x00000020; private const int idNotRequired = 0x00000040; private const int isNamingContainer = 0x00000080; private const int creatingControls = 0x00000100; private const int notVisibleOnPage = 0x00000200; private const int themeApplied = 0x00000400; private const int mustRenderID = 0x00000800; private const int disableTheming = 0x00001000; private const int enableThemingSet = 0x00002000; private const int styleSheetApplied = 0x00004000; private const int controlAdapterResolved = 0x00008000; private const int designMode = 0x00010000; private const int designModeChecked = 0x00020000; private const int disableChildControlState = 0x00040000; internal const int isWebControlDisabled = 0x00080000; private const int controlStateApplied = 0x00100000; private const int useGeneratedID = 0x00200000; #pragma warning disable 0649 internal SimpleBitVector32 flags; #pragma warning restore 0649 private const string automaticIDPrefix = "ctl"; private const string automaticLegacyIDPrefix = "_ctl"; private const int automaticIDCount = 128; private static readonly string[] automaticIDs = new string [automaticIDCount] { "ctl00", "ctl01", "ctl02", "ctl03", "ctl04", "ctl05", "ctl06", "ctl07", "ctl08", "ctl09", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15", "ctl16", "ctl17", "ctl18", "ctl19", "ctl20", "ctl21", "ctl22", "ctl23", "ctl24", "ctl25", "ctl26", "ctl27", "ctl28", "ctl29", "ctl30", "ctl31", "ctl32", "ctl33", "ctl34", "ctl35", "ctl36", "ctl37", "ctl38", "ctl39", "ctl40", "ctl41", "ctl42", "ctl43", "ctl44", "ctl45", "ctl46", "ctl47", "ctl48", "ctl49", "ctl50", "ctl51", "ctl52", "ctl53", "ctl54", "ctl55", "ctl56", "ctl57", "ctl58", "ctl59", "ctl60", "ctl61", "ctl62", "ctl63", "ctl64", "ctl65", "ctl66", "ctl67", "ctl68", "ctl69", "ctl70", "ctl71", "ctl72", "ctl73", "ctl74", "ctl75", "ctl76", "ctl77", "ctl78", "ctl79", "ctl80", "ctl81", "ctl82", "ctl83", "ctl84", "ctl85", "ctl86", "ctl87", "ctl88", "ctl89", "ctl90", "ctl91", "ctl92", "ctl93", "ctl94", "ctl95", "ctl96", "ctl97", "ctl98", "ctl99", "ctl100", "ctl101", "ctl102", "ctl103", "ctl104", "ctl105", "ctl106", "ctl107", "ctl108", "ctl109", "ctl110", "ctl111", "ctl112", "ctl113", "ctl114", "ctl115", "ctl116", "ctl117", "ctl118", "ctl119", "ctl120", "ctl121", "ctl122", "ctl123", "ctl124", "ctl125", "ctl126", "ctl127" }; ////// public Control() { if (this is INamingContainer) flags.Set(isNamingContainer); } ///Initializes a new instance of the ///class. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_ClientID) ] public virtual string ClientID { // This property is required to render a unique client-friendly id. get { // Ensure that ID is set. The assumption being made is that the caller // is likely to use the client ID in script, and to support that the // control should render out an ID attribute EnsureID(); string uniqueID = UniqueID; if(uniqueID != null && uniqueID.IndexOf(IdSeparator) >= 0) { return uniqueID.Replace(IdSeparator, ID_RENDER_SEPARATOR); } return uniqueID; } } protected char ClientIDSeparator { get { return ID_RENDER_SEPARATOR; } } ///Indicates the control identifier generated by the ASP.NET framework. This /// property is read-only. ////// [ WebSysDescription(SR.Control_OnDisposed) ] public event EventHandler Disposed { add { Events.AddHandler(EventDisposed, value); } remove { Events.RemoveHandler(EventDisposed, value); } } ///[To be supplied.] ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] protected internal virtual HttpContext Context { // Request context containing the intrinsics get { Page page = Page; if(page != null) { return page.Context; } return HttpContext.Current; } } protected virtual ControlAdapter ResolveAdapter() { if(flags[controlAdapterResolved]) { return _adapter; } if (DesignMode) { flags.Set(controlAdapterResolved); return null; } HttpContext context = Context; if (context != null) { _adapter = context.Request.Browser.GetAdapter(this); } flags.Set(controlAdapterResolved); return _adapter; } ///Gets the ///object of the current Web request. If /// the control's context is , this will be the context of the /// control's parent, unless the parent control's context is . /// If this is the case, this will be equal to the HttpContext property. /// protected ControlAdapter Adapter { get { if(flags[controlAdapterResolved]) { return _adapter; } _adapter = ResolveAdapter(); flags.Set(controlAdapterResolved); return _adapter; } } ///Indicates the list of event handler delegates for the control. This property /// is read-only. ////// Indicates whether a control is being used in the context of a design surface. /// protected internal bool DesignMode { get { if(!flags[designModeChecked]) { Page page = Page; if(page != null ) { if(page.GetDesignModeInternal()) { flags.Set(designMode); } else { flags.Clear(designMode); } } else { if(Site != null) { if(Site.DesignMode) { flags.Set(designMode); } else { flags.Clear(designMode); } } else if (Parent != null) { if(Parent.DesignMode) { flags.Set(designMode); } // VSWhidbey 535747: If Page, Site and Parent are all null, do not change the // designMode flag since it might had been previously set by the controlBuilder. // This does not affect runtime since designMode is by-default false. /* else { flags.Clear(designMode); } */ } } flags.Set(designModeChecked); } return flags[designMode]; } } // Helper function to call validateEvent. internal void ValidateEvent(string uniqueID) { ValidateEvent(uniqueID, String.Empty); } // Helper function to call validateEvent. internal void ValidateEvent(string uniqueID, string eventArgument) { if (Page != null && SupportsEventValidation) { Page.ClientScript.ValidateEvent(uniqueID, eventArgument); } } // Indicates whether the control supports event validation // By default, all web controls in System.Web assembly supports it but not custom controls. private bool SupportsEventValidation { get { return SupportsEventValidationAttribute.SupportsEventValidation(this.GetType()); } } ////// protected EventHandlerList Events { get { EnsureOccasionalFields(); if(_occasionalFields.Events == null) { _occasionalFields.Events = new EventHandlerList(); } return _occasionalFields.Events; } } protected bool HasEvents() { return ((_occasionalFields != null) && (_occasionalFields.Events != null)); } ///Indicates the list of event handler delegates for the control. This property /// is read-only. ////// [ ParenthesizePropertyName(true), MergableProperty(false), Filterable(false), Themeable(false), WebSysDescription(SR.Control_ID) ] public virtual string ID { get { if (!flags[idNotCalculated] && !flags[mustRenderID]) { return null; } return _id; } set { // allow the id to be unset if (value != null && value.Length == 0) value = null; string oldID = _id; _id = value; ClearCachedUniqueIDRecursive(); flags.Set(idNotCalculated); flags.Clear(useGeneratedID); // Update the ID in the naming container if ((_namingContainer != null) && (oldID != null)) { _namingContainer.DirtyNameTable(); } } } ///Gets or sets the identifier for the control. Setting the /// property on a control allows programmatic access to the control's properties. If /// this property is not specified on a control, either declaratively or /// programmatically, then you cannot write event handlers and the like for the control. ////// [ Browsable(false), DefaultValue(true), Themeable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_EnableTheming) ] public virtual bool EnableTheming { get { if (flags[enableThemingSet]) { return !flags[disableTheming]; } if (Parent != null) { return Parent.EnableTheming; } return !flags[disableTheming]; } set { if ((_controlState >= ControlState.FrameworkInitialized) && !DesignMode) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePreInitOrAddToControls, "EnableTheming")); } if(!value) { flags.Set(disableTheming); } else { flags.Clear(disableTheming); } flags.Set(enableThemingSet); } } // Serialzie the value if it's set explicitely. internal bool ShouldSerializeEnableTheming() { return flags[enableThemingSet];; } internal bool IsBindingContainer { get { return this is INamingContainer && !(this is INonBindingContainer); } } protected internal bool IsChildControlStateCleared { get { return flags[disableChildControlState]; } } ///Gets and sets a value indicating whether theme is enabled. ////// [ Browsable(false), DefaultValue(""), Filterable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_SkinId), ] public virtual string SkinID { get { if(_occasionalFields != null) { return _occasionalFields.SkinId == null ? String.Empty : _occasionalFields.SkinId; } return String.Empty; } set { if (!DesignMode) { if (flags[styleSheetApplied]) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforeStyleSheetApplied, "SkinId")); } if (_controlState >= ControlState.FrameworkInitialized) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePreInitOrAddToControls, "SkinId")); } } EnsureOccasionalFields(); _occasionalFields.SkinId = value; } } private ControlRareFields RareFieldsEnsured { get { EnsureOccasionalFields(); ControlRareFields rareFields = _occasionalFields.RareFields; if(rareFields == null) { rareFields = new ControlRareFields(); _occasionalFields.RareFields = rareFields; } return rareFields; } } private ControlRareFields RareFields { get { if(_occasionalFields != null) { return _occasionalFields.RareFields; } return null; } } private void EnsureOccasionalFields() { if(_occasionalFields == null) { _occasionalFields = new OccasionalFields(); } } ///Gets and sets the skinID of the control. ////// [ DefaultValue(EnableViewStateDefault), Themeable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_MaintainState) ] public virtual bool EnableViewState { get { return !flags[disableViewState]; } set { SetEnableViewStateInternal(value); } } internal void SetEnableViewStateInternal(bool value) { if (!value) flags.Set(disableViewState); else flags.Clear(disableViewState); } ////// Gets or sets a value indicating whether the control should maintain its view /// state, and the view state of any child control in contains, when the current /// page request ends. /// ////// Gets a value indicating whether the control is maintaining its view /// state, when the current page request ends by looking at its own EnableViewState /// value, and the value for all its parents. /// protected internal bool IsViewStateEnabled { get { Control current = this; while (current != null) { if (current.EnableViewState == false) { return false; } current = current.Parent; } return true; } } ////// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_NamingContainer) ] public virtual Control NamingContainer { get { if (_namingContainer == null) { if (Parent != null) { // Search for the closest naming container in the tree if (Parent.flags[isNamingContainer]) _namingContainer = Parent; else _namingContainer = Parent.NamingContainer; } } return _namingContainer; } } ///Gets the reference to the current control's naming container. ////// /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never) ] public Control BindingContainer { get { Control bindingContainer = NamingContainer; while (bindingContainer is INonBindingContainer) { bindingContainer = bindingContainer.BindingContainer; } return bindingContainer; } } ///Returns the databinding container of this control. In most cases, /// this is the same as the NamingContainer. But when using LoadTemplate(), /// we get into a situation where that is not the case (ASURT 94138) /// The behavior is different than V1 that Usercontrol.BindingContainer is no /// longer the UserControl but the control contains it. The behavior is consistent /// with LoadTemplate() case. ////// /// VSWhidbey 80467: Need to adapt id separator. /// protected char IdSeparator { get { if (Page != null) { return Page.IdSeparator; } return IdSeparatorFromConfig; } } // VSWhidbey 475945: Use the old id separator if configured internal char IdSeparatorFromConfig { get { return ((EnableLegacyRendering) ? LEGACY_ID_SEPARATOR : ID_SEPARATOR); } } // VSWhidbey 244374: Allow controls to opt into loading view state by ID instead of index (perf hit) protected bool LoadViewStateByID { get { return ViewStateModeByIdAttribute.IsEnabled(GetType()); } } ////// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Page) ] public virtual Page Page { get { if (_page == null) { if (Parent != null) { _page = Parent.Page; } } return _page; } set { if (OwnerControl != null) { throw new InvalidOperationException(); } // This is necessary because we need to set the page in generated // code before controls are added to the tree (ASURT 75330) Debug.Assert(_page == null); Debug.Assert(Parent == null || Parent.Page == null); _page = value; } } // VSWhidbey 244999 internal virtual bool IsReloadable { get { return false; } } // DevDiv 33149, 43258: A backward compat. switch for Everett rendering internal bool EnableLegacyRendering { get { Page page = Page; if (page != null) { return (page.XhtmlConformanceMode == XhtmlConformanceMode.Legacy); } else if (DesignMode || Adapter != null) { return false; } else { return (GetXhtmlConformanceSection().Mode == XhtmlConformanceMode.Legacy); } } } internal XhtmlConformanceSection GetXhtmlConformanceSection() { HttpContext context = Context; XhtmlConformanceSection xhtmlConformanceSection; if (context != null) { // if context is available, use the most efficient way to get the section xhtmlConformanceSection = RuntimeConfig.GetConfig(context).XhtmlConformance; } else { xhtmlConformanceSection = RuntimeConfig.GetConfig().XhtmlConformance; } Debug.Assert(xhtmlConformanceSection != null); return xhtmlConformanceSection; } #if ORCAS ///Gets the ///object that contains the /// current control. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Pager) ] public virtual ContentPager ContentPager { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.ContentPager == null) { if (Parent != null) { rareFields.ContentPager = Parent.ContentPager; } } return rareFields.ContentPager; } set { RareFieldsEnsured.ContentPager = value; } } #endif ///Gets the ///object that /// paginates the current control. /// internal virtual TemplateControl GetTemplateControl() { if(_templateControl == null) { if (Parent != null) { _templateControl = Parent.GetTemplateControl(); } } return _templateControl; } ///Gets the reference to the ////// that hosts the control. /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateControl) ] public TemplateControl TemplateControl { get { return GetTemplateControl(); } [EditorBrowsable(EditorBrowsableState.Never)] set { // This setter is necessary so that controls inside templates are based on // hosting pages not where the templates are used. _templateControl = value; } } /* * Determine whether this control is a descendent of the passed in control */ internal bool IsDescendentOf(Control ancestor) { Control current = this; while (current != ancestor && current.Parent != null) { current = current.Parent; } return (current == ancestor); } ///Gets the reference to the ////// that hosts the control. /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Parent) ] public virtual Control Parent { get { return _parent; } } internal bool IsParentedToUpdatePanel { get { Control parent = Parent; while (parent != null) { if (parent is IUpdatePanel) { return true; } parent = parent.Parent; } return false; } } ///Gets the current control's parent control in the UI hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateSourceDirectory) ] public virtual string TemplateSourceDirectory { get { if (TemplateControlVirtualDirectory == null) return String.Empty; return TemplateControlVirtualDirectory.VirtualPathStringNoTrailingSlash; } } ///Gets the virtual directory of the Page or UserControl that contains this control. ////// [ Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateSourceDirectory) ] public string AppRelativeTemplateSourceDirectory { get { return VirtualPath.GetAppRelativeVirtualPathStringOrEmpty(TemplateControlVirtualDirectory); } [EditorBrowsable(EditorBrowsableState.Never)] set { // This setter is necessary so that skins are based on hosting skin file. this.TemplateControlVirtualDirectory = VirtualPath.CreateNonRelativeAllowNull(value); } } internal VirtualPath TemplateControlVirtualDirectory { get { if (_templateSourceVirtualDirectory != null) return _templateSourceVirtualDirectory; TemplateControl control = TemplateControl; if (control == null) { HttpContext context = Context; if (context != null) { _templateSourceVirtualDirectory = context.Request.CurrentExecutionFilePathObject.Parent; } return _templateSourceVirtualDirectory; } // Prevent recursion if this is the TemplateControl if (control != this) { _templateSourceVirtualDirectory = control.TemplateControlVirtualDirectory; } return _templateSourceVirtualDirectory; } set { // This setter is necessary so that skins are based on hosting skin file. _templateSourceVirtualDirectory = value; } } internal ControlState ControlState { get { return _controlState; } set { _controlState = value; } } ///Gets the virtual directory of the Page or UserControl that contains this control. /// Unlike TemplateSourceDirectory, this returns an app relative path (e.g. "~/sub") ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Advanced), WebSysDescription(SR.Control_Site) ] public ISite Site { get { if (OwnerControl != null) { return OwnerControl.Site; } if (RareFields != null) { return RareFields.Site; } return null; } set { if (OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_SiteNotAllowed)); } RareFieldsEnsured.Site = value; flags.Clear(designModeChecked); } } ///Indicates the site information for the control. ////// [ Bindable(true), DefaultValue(true), WebCategory("Behavior"), WebSysDescription(SR.Control_Visible) ] public virtual bool Visible { get { if (flags[invisible]) return false; #if ORCAS if (NotVisibleOnPage) return false; #endif else if ((_parent != null) && !DesignMode) return _parent.Visible; else return true; } set { if (flags[marked]) { bool visible = !flags[invisible]; if (visible != value) { flags.Set(visibleDirty); } } if(!value) { flags.Set(invisible); } else { flags.Clear(invisible); } } } #if ORCAS internal bool ExplicitlyInvisible { get { return flags[invisible]; } } #endif ////// Gets or sets a value that indicates whether a control should be rendered on /// the page. /// ////// Do not remove or change the signature. It is called via reflection. /// This allows for correct serialization, since Visible is implemented as a /// recursive property. /// private void ResetVisible() { Visible = true; } ////// Do not remove or change the signature. It is called via reflection. /// This allows for correct serialization, since Visible is implemented as a /// recursive property. /// private bool ShouldSerializeVisible() { return flags[invisible]; } ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_UniqueID) ] public virtual string UniqueID { get { if (_cachedUniqueID != null) { return _cachedUniqueID; } Control namingContainer = NamingContainer; if (namingContainer != null) { // if the ID is null at this point, we need to have one created and the control added to the // naming container. if (_id == null) { GenerateAutomaticID(); } if (Page == namingContainer) { _cachedUniqueID = _id; } else { string uniqueIDPrefix = namingContainer.GetUniqueIDPrefix(); if (uniqueIDPrefix.Length == 0) { // In this case, it is probably a naming container that is not sited, so we don't want to cache it return _id; } else { _cachedUniqueID = uniqueIDPrefix + _id; } } return _cachedUniqueID; } else { // no naming container return _id; } } } #if SHIPPINGADAPTERS // Used by adapters in delegating rendering (e.g., a Button for a LinkButton for scriptless devices). // The UniqueID of the new control has to be set to match the UniqueID of the original. internal void SetUniqueID(string val) { _cachedUniqueID = val; } #endif ///Gets the unique, hierarchically-qualified identifier for /// a control. This is different from the ID property, in that the fully-qualified /// identifier includes the identifier for the control's naming container. ////// [ WebCategory("Data"), WebSysDescription(SR.Control_OnDataBind) ] public event EventHandler DataBinding { add { Events.AddHandler(EventDataBinding, value); } remove { Events.RemoveHandler(EventDataBinding, value); } } ///Occurs when the control binds to a data source. Notifies the control to perform any data binding during this event. ////// [ WebSysDescription(SR.Control_OnInit) ] public event EventHandler Init { add { Events.AddHandler(EventInit, value); } remove { Events.RemoveHandler(EventInit, value); } } ///Occurs when the control is initialized, the first step in the page lifecycle. Controls should /// perform any initialization steps that are required to create and set up an /// instantiation. ////// [ WebSysDescription(SR.Control_OnLoad) ] public event EventHandler Load { add { Events.AddHandler(EventLoad, value); } remove { Events.RemoveHandler(EventLoad, value); } } ///Occurs when the control is loaded to the ///object. Notifies the control to perform any steps that /// need to occur on each page request. /// [ WebSysDescription(SR.Control_OnPreRender) ] public event EventHandler PreRender { add { Events.AddHandler(EventPreRender, value); } remove { Events.RemoveHandler(EventPreRender, value); } } ///Occurs when the control is about to render. Controls /// should perform any pre-rendering steps necessary before saving view state and /// rendering content to the ///object. /// [ WebSysDescription(SR.Control_OnUnload) ] public event EventHandler Unload { add { Events.AddHandler(EventUnload, value); } remove { Events.RemoveHandler(EventUnload, value); } } ///Occurs when the control is unloaded from memory. Controls should perform any /// final cleanup before this instance of it is ////// [ EditorBrowsable(EditorBrowsableState.Advanced), ] public virtual void ApplyStyleSheetSkin(Page page) { // Nothing to do if the control is not in a Page. if (page == null) { return; } // Only apply stylesheet if not already applied. if (flags[styleSheetApplied]) { throw new InvalidOperationException(SR.GetString(SR.StyleSheetAreadyAppliedOnControl)); } if (page.ApplyControlStyleSheet(this)) { flags.Set(styleSheetApplied); } } ///Apply stylesheet skin on the control. ////// private void ApplySkin(Page page) { if (page == null) { throw new ArgumentNullException("page"); } if (flags[themeApplied]) { return; } if (ThemeableAttribute.IsTypeThemeable(this.GetType())) { page.ApplyControlSkin(this); flags.Set(themeApplied); } } ///Apply theme on the control. ////// protected virtual void OnDataBinding(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventDataBinding] as EventHandler; if(handler != null) { handler(this, e); } } } ///Raises the ///event. This /// notifies a control to perform any data binding logic that is associated with it. /// public virtual void DataBind() { DataBind(true); } ///Causes data binding to occur on the invoked control and all of its child /// controls. ////// protected virtual void DataBind(bool raiseOnDataBinding) { bool inDataBind = false; if (IsBindingContainer) { bool foundDataItem; object dataItem = DataBinder.GetDataItem(this, out foundDataItem); if (foundDataItem && (Page != null)) { Page.PushDataBindingContext(dataItem); inDataBind = true; } } try { if (raiseOnDataBinding) { // Do our own databinding OnDataBinding(EventArgs.Empty); } // Do all of our children's databinding DataBindChildren(); } finally { if (inDataBind) { Page.PopDataBindingContext(); } } } ///Causes the invoked controls' context to be pushed on the stack, /// then conditionally call OnDataBinging on the invoked control, and databind all of its child /// controls. A control would call this with false if it overrides DataBind without calling /// Control.DataBind, but still wants to be an IDataItemContainer. FormView and DetailsView /// are good examples of this. ////// protected virtual void DataBindChildren() { if (HasControls()) { EnsureOccasionalFields(); string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); try { try { int controlCount = _occasionalFields.Controls.Count; for (int i=0; i < controlCount; i++) _occasionalFields.Controls[i].DataBind(); } finally { _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } } catch { throw; } } } internal void PreventAutoID() { // controls that are also naming containers must always get an id if (flags[isNamingContainer] == false) { flags.Set(idNotRequired); } } ///Causes data binding to occur on all of the child controls. ////// protected virtual void AddParsedSubObject(object obj) { Control control = obj as Control; if (control != null) { Controls.Add(control); } } private void UpdateNamingContainer(Control namingContainer) { // Remove the cached uniqueID if the control already had a namingcontainer // and the namingcontainer is changed. if (_namingContainer != null && _namingContainer != namingContainer) { ClearCachedUniqueIDRecursive(); } _namingContainer = namingContainer; } private void ClearCachedUniqueIDRecursive() { _cachedUniqueID = null; if (_occasionalFields != null) { _occasionalFields.UniqueIDPrefix = null; if (_occasionalFields.Controls != null) { int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].ClearCachedUniqueIDRecursive(); } } } } protected void EnsureID() { if (_namingContainer != null) { if (_id == null) { GenerateAutomaticID(); } flags.Set(mustRenderID); } } private void GenerateAutomaticID() { Debug.Assert(_namingContainer != null); Debug.Assert(_id == null); // Remember that a generated ID is used for this control. flags.Set(useGeneratedID); // Calculate the automatic ID. For performance and memory reasons // we look up a static table entry if possible _namingContainer.EnsureOccasionalFields(); int idNo = _namingContainer._occasionalFields.NamedControlsID++; if (EnableLegacyRendering) { // VSWhidbey 517118 _id = automaticLegacyIDPrefix + idNo.ToString(NumberFormatInfo.InvariantInfo); } else { if (idNo < automaticIDCount) { _id = automaticIDs[idNo]; } else { _id = automaticIDPrefix + idNo.ToString(NumberFormatInfo.InvariantInfo); } } _namingContainer.DirtyNameTable(); } internal virtual string GetUniqueIDPrefix() { EnsureOccasionalFields(); if (_occasionalFields.UniqueIDPrefix == null) { string uniqueID = UniqueID; if (!String.IsNullOrEmpty(uniqueID)) { _occasionalFields.UniqueIDPrefix = uniqueID + IdSeparator; } else { _occasionalFields.UniqueIDPrefix = String.Empty; } } return _occasionalFields.UniqueIDPrefix; } ///Notifies the control that an element, XML or HTML, was parsed, and adds it to /// the control. ////// protected internal virtual void OnInit(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventInit] as EventHandler; if(handler != null) { handler(this, e); } } } internal virtual void InitRecursive(Control namingContainer) { ResolveAdapter(); if (_occasionalFields != null && _occasionalFields.Controls != null) { if (flags[isNamingContainer]) { namingContainer = this; } string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { Control control = _occasionalFields.Controls[i]; // Propagate the page and namingContainer control.UpdateNamingContainer(namingContainer); if ((control._id == null) && (namingContainer != null) && !control.flags[idNotRequired]) { control.GenerateAutomaticID(); } control._page = Page; control.InitRecursive(namingContainer); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } // Only make the actual call if it hasn't already happened (ASURT 111303) if (_controlState < ControlState.Initialized) { _controlState = ControlState.ChildrenInitialized; // framework also initialized if ((Page != null) && !DesignMode) { if (Page.ContainsTheme && EnableTheming) { ApplySkin(Page); } } if (_adapter != null) { _adapter.OnInit(EventArgs.Empty); } else { OnInit(EventArgs.Empty); } _controlState = ControlState.Initialized; } // track all subsequent state changes TrackViewState(); #if DEBUG ControlInvariant(); #endif } #if DEBUG ///Raises the ///event. This notifies the control to perform /// any steps necessary for its creation on a page request. /// internal void ControlInvariant() { // If the control is initialized, the naming container and page should have been pushed in if (_controlState >= ControlState.Initialized) { if (DesignMode) { // Top-level UserControls do not have a page or a naming container in the designer // hence the special casing. Debug.Assert((_namingContainer != null) || (this is Page) || (this is UserControl)); // } else { if (!(this is Page)) { Debug.Assert(_namingContainer != null); } Debug.Assert(Page != null); } } // If naming container is set and the name table exists, the ID should exist in it. if(_namingContainer != null && _namingContainer._occasionalFields != null && _namingContainer._occasionalFields.NamedControls != null && _id != null) { Debug.Assert(_namingContainer._occasionalFields.NamedControls.Contains(_id)); } } // Collect some statistic about the number of controls with occasional and // rare fields. internal void GetRareFieldStatistics(ref int totalControls, ref int withOccasionalFields, ref int withRareFields) { totalControls++; if (_occasionalFields != null) { withOccasionalFields++; if (_occasionalFields.RareFields != null) withRareFields++; // No children: we're done if (_occasionalFields.Controls == null) return; int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { Control control = _occasionalFields.Controls[i]; control.GetRareFieldStatistics(ref totalControls, ref withOccasionalFields, ref withRareFields); } } } #endif protected void ClearChildState() { ClearChildControlState(); ClearChildViewState(); } protected void ClearChildControlState() { //VSWhidbey 242621 to be consistent with ClearChildViewState, ignore calls before and during Init if (ControlState < ControlState.Initialized) { return; } flags.Set(disableChildControlState); if (Page != null) { Page.RegisterRequiresClearChildControlState(this); } } ///This should be used to assert internal state about the control ////// protected void ClearChildViewState() { if(_occasionalFields != null) { _occasionalFields.ControlsViewState = null; } } ///Deletes the view state information for all of the current control's child /// controls. ////// protected bool HasChildViewState { get { return ((_occasionalFields != null) && (_occasionalFields.ControlsViewState != null) && (_occasionalFields.ControlsViewState.Count > 0)); } } ///Indicates whether the current control's children have any saved view state /// information. This property is read-only. ////// Sets initial focus on the control /// public virtual void Focus() { Page.SetFocus(this); } internal void LoadControlStateInternal(object savedStateObj) { // Do not load the control state if it has been applied. if (flags[controlStateApplied]) { return; } flags.Set(controlStateApplied); Pair savedState = (Pair)savedStateObj; if (savedState == null) { return; } Page page = Page; if (page != null && !page.ShouldLoadControlState(this)) { return; } // VSWhidbey160650: Only call LoadControlState with non null savedState if (savedState.First != null) { LoadControlState(savedState.First); } // VSWhidbey356804: Only call LoadAdapterControlState with non null savedState if (_adapter == null || savedState.Second == null) { return; } _adapter.LoadAdapterControlState(savedState.Second); } ////// Load the control state, which is the essential state information needed even if view state is disabled. /// protected internal virtual void LoadControlState(object savedState) { } ////// protected virtual void LoadViewState(object savedState) { if (savedState != null) { ViewState.LoadViewState(savedState); // Load values cached out of view state object visible = ViewState["Visible"]; if (visible != null) { if(!(bool)visible) { flags.Set(invisible); } else { flags.Clear(invisible); } flags.Set(visibleDirty); } } } internal void LoadViewStateRecursive(object savedState) { // nothing to do if we have no state if (savedState == null || flags[disableViewState]) return; if (Page != null && Page.IsPostBack) { object controlState = null; object adapterState = null; ArrayList childState = null; Pair allSavedState = savedState as Pair; if (allSavedState != null) { controlState = allSavedState.First; childState = (ArrayList)allSavedState.Second; } else { Debug.Assert(savedState is Triplet); Triplet t = (Triplet)savedState; controlState = t.First; adapterState = t.Second; childState = (ArrayList)t.Third; } try { if ((adapterState != null) && (_adapter != null)) { _adapter.LoadAdapterViewState(adapterState); } if (controlState != null) { LoadViewState(controlState); } if (childState != null) { if (LoadViewStateByID) { LoadChildViewStateByID(childState); } else { LoadChildViewStateByIndex(childState); } } } catch (InvalidCastException) { // catch all viewstate loading problems with casts. They are most likely changed control trees. throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts)); } catch (IndexOutOfRangeException) { // catch all viewstate loading problems with indeces. They are most likely changed control trees. throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts)); } } _controlState = ControlState.ViewStateLoaded; } internal void LoadChildViewStateByID(ArrayList childState) { int childStateCount = childState.Count; for (int i = 0; i < childStateCount; i += 2) { // first element is index or ID of control with state and the // next element is state of the control string controlId = (string)childState[i]; object state = childState[i + 1]; Control childControl = FindControl(controlId); if (childControl != null) { childControl.LoadViewStateRecursive(state); } else { // couldn't find a control for this state blob, save it for later EnsureOccasionalFields(); if (_occasionalFields.ControlsViewState == null) { _occasionalFields.ControlsViewState = new Hashtable(); } _occasionalFields.ControlsViewState[controlId] = state; } } } internal void LoadChildViewStateByIndex(ArrayList childState) { ControlCollection ctrlColl = Controls; int ctrlCount = ctrlColl.Count; int childStateCount = childState.Count; for (int i = 0; i < childStateCount; i += 2) { // first element is index of control with state and the // next element is state of the control int controlIndex = (int)childState[i]; object state = childState[i + 1]; if (controlIndex < ctrlCount) { // we have a control for this state blob ctrlColl[controlIndex].LoadViewStateRecursive(state); } else { // couldn't find a control for this state blob, save it for later EnsureOccasionalFields(); if (_occasionalFields.ControlsViewState == null) { _occasionalFields.ControlsViewState = new Hashtable(); } _occasionalFields.ControlsViewState[controlIndex] = state; } } } /// /// Figure out if a path is physical or virtual. This is useful because a number of our controls /// accept either type of path for the same attribute. /// internal void ResolvePhysicalOrVirtualPath(string path, out VirtualPath virtualPath, out string physicalPath) { if (System.Web.Util.UrlPath.IsAbsolutePhysicalPath(path)) { physicalPath = path; virtualPath = null; } else { physicalPath = null; // It could be relative, so resolve it virtualPath = TemplateControlVirtualDirectory.Combine(VirtualPath.Create(path)); } } ///Restores the view state information from a previous page /// request that was saved by the Control.SavedState method. ////// protected internal string MapPathSecure(string virtualPath) { if (String.IsNullOrEmpty(virtualPath)) { throw new ArgumentNullException("virtualPath", SR.GetString(SR.VirtualPath_Length_Zero)); } string physicalPath; VirtualPath virtualPathObject; ResolvePhysicalOrVirtualPath(virtualPath, out virtualPathObject, out physicalPath); if (physicalPath == null) { physicalPath = virtualPathObject.MapPathInternal(TemplateControlVirtualDirectory, true /*allowCrossAppMapping*/); } // Security check HttpRuntime.CheckFilePermission(physicalPath); return physicalPath; } ////// This function takes a virtual path, that is a relative or root relative URL without a protocol. /// It returns the mapped physcial file name relative to the template source. It throws an exception if /// there is insufficient security access to read or investigate the mapped result. This should be used /// by controls that can read files and live in fully trusted DLLs such as System.Web.dll to prevent /// security issues. The exception thrown does not give away information about the mapping. For absolute /// physical paths, this function checks permission /// ////// protected internal Stream OpenFile(string path) { string physicalPath = null; VirtualFile vfile = null; // Need to Trim it since MapPath no longer allows trailing space (VSWhidbey 441210) path = path.Trim(); if (UrlPath.IsAbsolutePhysicalPath(path)) { // Absolute physical path physicalPath = path; } else { vfile = HostingEnvironment.VirtualPathProvider.GetFile(path); MapPathBasedVirtualFile mapPathVFile = vfile as MapPathBasedVirtualFile; if (mapPathVFile != null) { physicalPath = mapPathVFile.PhysicalPath; } } // If we got a physical path, make sure the user has access to it if (physicalPath != null) { HttpRuntime.CheckFilePermission(physicalPath); } if (vfile != null) { return vfile.Open(); } else { return new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read); } } /// /// Open a stream from either a virtual or physical path, and if possible get a CacheDependency /// for the resulting Stream. /// internal Stream OpenFileAndGetDependency(VirtualPath virtualPath, string physicalPath, out CacheDependency dependency) { // Only one of the paths should be non-null Debug.Assert((virtualPath == null) != (physicalPath == null)); // If we got a virtual path, and we're using the default VPP, call MapPath if (physicalPath == null && HostingEnvironment.UsingMapPathBasedVirtualPathProvider) { physicalPath = virtualPath.MapPathInternal(TemplateControlVirtualDirectory, true /*allowCrossAppMapping*/); } Stream stream; if (physicalPath != null) { // Security check HttpRuntime.CheckFilePermission(physicalPath); // Work directly with the physical file, bypassing the VPP stream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read); dependency = new CacheDependency(0, physicalPath); } else { // It's non file system based, so go though the VirtualPathProvider stream = virtualPath.OpenFile(); dependency = VirtualPathProvider.GetCacheDependency(virtualPath); } return stream; } ////// This function takes a virtual path, that is a relative or root relative URL without a protocol. /// It can also take a physical path, either local (c:\) or UNC. /// It returns a stream used to read to contents of the file. It throws an exception if /// there is insufficient security access to read or investigate the mapped result. This should be used /// by controls that can read files and live in fully trusted DLLs such as System.Web.dll to prevent /// security issues. The exception thrown does not give away information about the mapping. For absolute /// physical paths, this function checks permission /// ////// protected internal virtual void OnLoad(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventLoad] as EventHandler; if(handler != null) { handler(this, e); } } } internal virtual void LoadRecursive() { // Only make the actual call if it hasn't already happened (ASURT 111303) if (_controlState < ControlState.Loaded) { if(_adapter != null) { _adapter.OnLoad(EventArgs.Empty); } else { OnLoad(EventArgs.Empty); } } // Call Load on all our children if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].LoadRecursive(); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } if (_controlState < ControlState.Loaded) _controlState = ControlState.Loaded; } ///Raises the ////// event. This notifies the control that it should perform any work that needs to /// occur for each page request. /// protected internal virtual void OnPreRender(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventPreRender] as EventHandler; if (handler != null) { handler(this, e); } } } internal virtual void PreRenderRecursiveInternal() { // Call Visible property and cache value in !flags[invisible] to allow Visible to be overridden. // This avoids unnecessary virtual property calls in SaveViewState and Render. bool visible = Visible; if(!visible) { flags.Set(invisible); } else { flags.Clear(invisible); EnsureChildControls(); if(_adapter != null) { _adapter.OnPreRender(EventArgs.Empty); } else { OnPreRender(EventArgs.Empty); } if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i=0; i < controlCount; i++) { _occasionalFields.Controls[i].PreRenderRecursiveInternal(); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } } _controlState = ControlState.PreRendered; } internal int EstimateStateSize(object state) { if(state == null) { return 0; } return Util.SerializeWithAssert(new ObjectStateFormatter(), state).Length; } /* * Walk the tree and fill in profile information */ ///Raises the ///event. This method uses event arguments /// to pass the event data to the control. /// /// protected void BuildProfileTree(string parentId, bool calcViewState) { // estimate the viewstate size. calcViewState = calcViewState && (!flags[disableViewState]); int viewstatesize; if (calcViewState) viewstatesize = EstimateStateSize(SaveViewState()); else viewstatesize = 0; int controlstatesize = 0; if(Page != null && Page._registeredControlsRequiringControlState != null && Page._registeredControlsRequiringControlState.Contains(this)) { controlstatesize = EstimateStateSize(SaveControlStateInternal()); } // give it all to the profiler Page.Trace.AddNewControl(UniqueID, parentId, this.GetType().FullName, viewstatesize, controlstatesize); if (_occasionalFields != null && _occasionalFields.Controls != null) { int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].BuildProfileTree(UniqueID, calcViewState); } } } internal object SaveControlStateInternal() { object controlState = SaveControlState(); object adapterControlState = null; if (_adapter != null) { adapterControlState = _adapter.SaveAdapterControlState(); } if (controlState != null || adapterControlState != null) { return new Pair(controlState, adapterControlState); } return null; } ///Gathers information about the control and delivers it to the ////// property to be displayed when tracing is enabled for the page. /// Save the control state, which is the essential state information needed even if view state is disabled. /// protected internal virtual object SaveControlState() { return null; } // Save modified state the control would like restored on the postback. // Return null if there is no state to save. ////// protected virtual object SaveViewState() { // Save values cached out of view state if (flags[visibleDirty]) { ViewState["Visible"] = !flags[invisible]; } if (_viewState != null) return _viewState.SaveViewState(); return null; } // Answer any state this control or its descendants want to save on freeze. // The format for saving is Triplet(myState, ArrayList childIDs, ArrayList childStates), // where myState or childStates and childIDs may be null. internal object SaveViewStateRecursive() { if (flags[disableViewState]) return null; object adapterState = null; if (_adapter != null) { adapterState = _adapter.SaveAdapterViewState(); } object controlSavedState = SaveViewState(); ArrayList childStates = null; if (HasControls()) { ControlCollection occasionalFieldControls = _occasionalFields.Controls; int occasionalFieldControlCount = occasionalFieldControls.Count; bool useId = LoadViewStateByID; for (int i = 0; i < occasionalFieldControlCount; i++) { Control child = occasionalFieldControls[i]; object childState = child.SaveViewStateRecursive(); if (childState != null) { if (childStates == null) { childStates = new ArrayList(occasionalFieldControlCount); } if (useId) { child.EnsureID(); childStates.Add(child.ID); } else { childStates.Add(i); } childStates.Add(childState); } } } if (_adapter != null) { if ((controlSavedState != null) || (adapterState != null) || (childStates != null)) { return new Triplet(controlSavedState, adapterState, childStates); } } else { if ((controlSavedState != null) || (childStates != null)) { return new Pair(controlSavedState, childStates); } } return null; } ////// Saves view state for use with a later ////// request. /// /// protected internal virtual void Render(HtmlTextWriter writer) { RenderChildren(writer); } internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children) { // If we have a delegate, use it for the rendering. // This happens when there is some ASP code. See also Whidbey 33012. if(RareFields != null && RareFields.RenderMethod != null ) { writer.BeginRender(); RareFields.RenderMethod(writer, this); writer.EndRender(); return; } if (children != null) { foreach (Control child in children) { child.RenderControl(writer); } } } protected internal virtual void RenderChildren(HtmlTextWriter writer) { ICollection children = (_occasionalFields == null) ? null : _occasionalFields.Controls; RenderChildrenInternal(writer, children); } ///Outputs control content to a provided HTMLTextWriter /// output stream. ////// public virtual void RenderControl(HtmlTextWriter writer) { //use the Adapter property to ensure it is resolved RenderControl(writer, Adapter); } ///[To be supplied.] ////// protected void RenderControl(HtmlTextWriter writer, ControlAdapter adapter) { if (!flags[invisible] && !flags[notVisibleOnPage]) { HttpContext context = (Page == null) ? null : Page._context; if (context != null && context.TraceIsEnabled) { int presize = context.Response.GetBufferedLength(); RenderControlInternal(writer, adapter); int postsize = context.Response.GetBufferedLength(); context.Trace.AddControlSize(UniqueID, postsize - presize); } else { RenderControlInternal(writer, adapter); } } } private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) { if (adapter != null) { // adapter.BeginRender(writer); adapter.Render(writer); adapter.EndRender(writer); } else { Render(writer); } } ///Used for MobilePage implementation. ////// protected internal virtual void OnUnload(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventUnload] as EventHandler; if (handler != null) { handler(this, e); } } } ///[To be supplied.] ////// public virtual void Dispose() { IContainer container = null; if (Site != null) { container = (IContainer)Site.GetService(typeof(IContainer)); if (container != null) { container.Remove(this); EventHandler disp = Events[EventDisposed] as EventHandler; if (disp != null) disp(this, EventArgs.Empty); } } if (_occasionalFields != null) { _occasionalFields.Dispose(); //do not null out for backwards compat, VSWhidbey 475940 //_occasionalFields = null; } } internal virtual void UnloadRecursive(bool dispose) { Page page = Page; if (page != null && page.RequiresControlState(this)) { page.UnregisterRequiresControlState(this); RareFieldsEnsured.RequiredControlState = true; } // Remove the generated ID so it will be assigned a different ID next time. if (flags[useGeneratedID]) { _id = null; flags.Clear(useGeneratedID); } if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) _occasionalFields.Controls[i].UnloadRecursive(dispose); _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } if(_adapter != null) { _adapter.OnUnload(EventArgs.Empty); } else { OnUnload(EventArgs.Empty); } // if (dispose) Dispose(); // VSWhidbey 244999: Everett behavior doesn't reset the control state. // But for control which requires its OnInit method to be called again // to properly initialize when the control is removed and added back // to Page's control tree, the control can override IsReloadable // to true so the control state is reset. e.g. Validator, see bug if (IsReloadable) { _controlState = ControlState.Constructed; } } ///Enables a control to perform final cleanup. ////// protected void RaiseBubbleEvent(object source, EventArgs args) { Control currentTarget = Parent; while (currentTarget != null) { if (currentTarget.OnBubbleEvent(source, args)) { return; } currentTarget = currentTarget.Parent; } } ///Assigns an sources of the event and its information up the page control /// hierarchy until they reach the top of the control tree. ////// protected virtual bool OnBubbleEvent(object source, EventArgs args) { return false; } // Members related to being a container ///Determines whether the event for the control should be passed up the page's /// control hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Controls) ] public virtual ControlCollection Controls { get { if (_occasionalFields == null || _occasionalFields.Controls == null) { EnsureOccasionalFields(); _occasionalFields.Controls = CreateControlCollection(); } return _occasionalFields.Controls; } } ///Gets a ControlCollection object that represents the child controls for a specified control in the /// UI hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_State) ] protected virtual StateBag ViewState { get { if (_viewState != null) { // create a StateBag on demand; WebControl makes its case sensitive return _viewState; } _viewState = new StateBag(ViewStateIgnoresCase); if (IsTrackingViewState) _viewState.TrackViewState(); return _viewState; } } // fast enough that we cam always use it. ///Indicates a dictionary of state information that allows you to save and restore /// the state of a control across multiple requests for the same page. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), ] protected virtual bool ViewStateIgnoresCase { get { return false; } } ///Indicates whether the ///object is case-insensitive. /// protected internal virtual void AddedControl(Control control, int index) { if (control.OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_NotAllowed)); } if (control._parent != null) { control._parent.Controls.Remove(control); } control._parent = this; control._page = Page; control.flags.Clear(designModeChecked); // We only add to naming container if it is available. Otherwise, it will be pushed through // during InitRecursive Control namingContainer = flags[isNamingContainer] ? this : _namingContainer; if (namingContainer != null) { control.UpdateNamingContainer(namingContainer); if (control._id == null && !control.flags[idNotRequired]) { // this will also dirty the name table in the naming container control.GenerateAutomaticID(); } else if (control._id != null || (control._occasionalFields != null && control._occasionalFields.Controls != null)) { // If the control has and ID, or has children (which *may* themselves // have ID's), we need to dirty the name table (ASURT 100557) namingContainer.DirtyNameTable(); } } /* * The following is for times when AddChild is called after CreateChildControls. This * allows users to add children at any time in the creation process without having * to understand the underlying machinery. * Note that if page is null, it means we haven't been attached to a container ourselves. * If this is true, when we are, our children will be recursively set up. */ if (_controlState >= ControlState.ChildrenInitialized) { Debug.Assert(namingContainer != null); control.InitRecursive(namingContainer); // VSWhidbey 396372: We need to reregister the control state if the control is reparented because the control // is unregistered during unload, but its already been inited once, so it will not get its Init called again // which is where most controls call RegisterRequiresControlState if (control._controlState >= ControlState.Initialized && control.RareFields != null && control.RareFields.RequiredControlState) { Page.RegisterRequiresControlState(control); } if (_controlState >= ControlState.ViewStateLoaded) { object viewState = null; if(_occasionalFields != null && _occasionalFields.ControlsViewState != null) { viewState = _occasionalFields.ControlsViewState[index]; // This solution takes the conservative approach that once viewstate has been // applied to a child control, it is thrown away. This eliminates inadvertently // setting viewstate on the wrong control, which can occur in scenarios where // the child control collection is being manipulated via code. Probably need // to provide a feature where programmer can control whether to reapply viewstate // or not. if (LoadViewStateByID) { control.EnsureID(); viewState = _occasionalFields.ControlsViewState[control.ID]; _occasionalFields.ControlsViewState.Remove(control.ID); } else { viewState = _occasionalFields.ControlsViewState[index]; _occasionalFields.ControlsViewState.Remove(index); } } control.LoadViewStateRecursive(viewState); if (_controlState >= ControlState.Loaded) { control.LoadRecursive(); if (_controlState >= ControlState.PreRendered) control.PreRenderRecursiveInternal(); } } } } ////// protected virtual ControlCollection CreateControlCollection() { return new ControlCollection(this); } ///[To be supplied.] ////// protected internal virtual void CreateChildControls() { } ////// Notifies any controls that use composition-based implementation to create any /// child controls they contain in preperation for postback or rendering. /// ////// protected bool ChildControlsCreated { get { return flags[controlsCreated]; } set { if (!value && flags[controlsCreated]) { Controls.Clear(); } if(value) { flags.Set(controlsCreated); } else { flags.Clear(controlsCreated); } } } ///Indicates whether the control's child controls have been created. ////// public string ResolveUrl(string relativeUrl) { if (relativeUrl == null) { throw new ArgumentNullException("relativeUrl"); } // check if its empty or already absolute if ((relativeUrl.Length == 0) || (UrlPath.IsRelativeUrl(relativeUrl) == false)) { return relativeUrl; } string baseUrl = AppRelativeTemplateSourceDirectory; if (String.IsNullOrEmpty(baseUrl)) { return relativeUrl; } // first make it absolute string url = UrlPath.Combine(baseUrl, relativeUrl); // include the session cookie if available (ASURT 47658) // As a side effect, this will change an app relative path (~/...) to app absolute return Context.Response.ApplyAppPathModifier(url); } ///Make a URL absolute using the AppRelativeTemplateSourceDirectory. The returned URL is for /// client use, and will contain the session cookie if appropriate. ////// public string ResolveClientUrl(string relativeUrl) { if (DesignMode && Page != null && Page.Site != null) { IUrlResolutionService resolutionService = (IUrlResolutionService)Page.Site.GetService(typeof(IUrlResolutionService)); if (resolutionService != null) { return resolutionService.ResolveClientUrl(relativeUrl); } } if (relativeUrl == null) { throw new ArgumentNullException("relativeUrl"); } // Get the app absolute TemplateSourceDirectory (not app relative) string tplSourceDir = VirtualPath.GetVirtualPathString(TemplateControlVirtualDirectory); if (String.IsNullOrEmpty(tplSourceDir)) return relativeUrl; string baseRequestDir = Context.Request.ClientBaseDir.VirtualPathString; // If the path is app relative (~/...), we cannot take shortcuts, since // the ~ is meaningless on the client, and must be resolved if (!UrlPath.IsAppRelativePath(relativeUrl)) { // If the template source directory is the same as the directory of the request, // we don't need to do any adjustments to the input path if (StringUtil.EqualsIgnoreCase(baseRequestDir, tplSourceDir)) return relativeUrl; // check if it's empty or absolute if ((relativeUrl.Length == 0) || (!UrlPath.IsRelativeUrl(relativeUrl))) { return relativeUrl; } } // first make it absolute string url = UrlPath.Combine(tplSourceDir, relativeUrl); // Make sure the path ends with a slash before calling MakeRelative baseRequestDir = UrlPath.AppendSlashToPathIfNeeded(baseRequestDir); // Now, make it relative to the current request, so that the client will // compute the correct path return HttpUtility.UrlPathEncode(UrlPath.MakeRelative(baseRequestDir, url)); } internal void DirtyNameTable() { Debug.Assert(this is INamingContainer); if(_occasionalFields != null) { _occasionalFields.NamedControls = null; } } private void EnsureNamedControlsTable() { Debug.Assert(this is INamingContainer); Debug.Assert(HasControls()); Debug.Assert(_occasionalFields != null); Debug.Assert(_occasionalFields.NamedControls == null); _occasionalFields.NamedControls = new HybridDictionary(/*initialSize*/ _occasionalFields.NamedControlsID, /*caseInsensitive*/ true); FillNamedControlsTable(this, _occasionalFields.Controls); } private void FillNamedControlsTable(Control namingContainer, ControlCollection controls) { Debug.Assert(namingContainer._occasionalFields != null); Debug.Assert(namingContainer._occasionalFields.NamedControls != null); Debug.Assert((controls != null) && (controls.Count != 0)); int controlCount = controls.Count; for (int i=0; i < controlCount; i++) { Control control = controls[i]; if (control._id != null) { #if DEBUG if (control._namingContainer != null) { Debug.Assert(control._namingContainer == namingContainer); } #endif // DEBUG try { namingContainer.EnsureOccasionalFields(); namingContainer._occasionalFields.NamedControls.Add(control._id, control); } catch { throw new HttpException(SR.GetString(SR.Duplicate_id_used, control._id, "FindControl")); } } if (control.HasControls() && (control.flags[isNamingContainer] == false)) { FillNamedControlsTable(namingContainer, control.Controls); } } } ///Return a URL that is suitable for use on the client. /// If the URL is absolute, return it unchanged. If it is relative, turn it into a /// relative URL that is correct from the point of view of the current request path /// (which is what the browser uses for resolution). ////// public virtual Control FindControl(String id) { return FindControl(id, 0); } ///Searches the current naming container for a control with /// the specified ///. /// /// protected virtual Control FindControl(String id, int pathOffset) { string childID; EnsureChildControls(); // If we're not the naming container, let it do the job if (!(flags[isNamingContainer])) { Control namingContainer = NamingContainer; if (namingContainer != null) { return namingContainer.FindControl(id, pathOffset); } return null; } // No registered control, demand create the named controls table //call HasControls ensuress _occasionalFields != null if(HasControls() && _occasionalFields.NamedControls == null) { EnsureNamedControlsTable(); } if (_occasionalFields == null || _occasionalFields.NamedControls == null) { return null; } // Need to support ':' for V1 backward compatibility. char[] findControlSeparators = { ID_SEPARATOR, LEGACY_ID_SEPARATOR }; // Is it a hierarchical name? int newPathOffset = id.IndexOfAny(findControlSeparators, pathOffset); // If not, handle it here if (newPathOffset == -1) { childID = id.Substring(pathOffset); return _occasionalFields.NamedControls[childID] as Control; } // Get the name of the child, and try to locate it childID = id.Substring(pathOffset, newPathOffset - pathOffset); Control child = _occasionalFields.NamedControls[childID] as Control; // Child doesn't exist: fail if (child == null) return null; return child.FindControl(id, newPathOffset + 1); } /* * Called when the controls of a naming container are cleared. */ internal void ClearNamingContainer() { Debug.Assert(this is INamingContainer); EnsureOccasionalFields(); _occasionalFields.NamedControlsID = 0; DirtyNameTable(); } ///Searches the current naming container for a control with the specified /// ///and an offset to aid in the /// search. /// /// [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] protected virtual IDictionary GetDesignModeState() { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.DesignModeState == null) { rareFields.DesignModeState = new HybridDictionary(); } return rareFields.DesignModeState; } ////// public virtual bool HasControls() { return _occasionalFields != null && _occasionalFields.Controls != null && _occasionalFields.Controls.Count > 0; } /* * Check if a Control either has children or has a compiled render method. * This is to address issues like ASURT 94127 */ internal bool HasRenderingData() { return HasControls() || HasRenderDelegate(); } /* * Check if a Control either has children or has a compiled render method. * This is to address issues like ASURT 94127 */ internal bool HasRenderDelegate() { if(RareFields != null) { return (RareFields.RenderMethod != null ); } return false; } /* * Returns true if the container contains just a static string, i.e., * when the Controls collection has a single LiteralControl. */ ///Determines if the current control contains any child /// controls. Since this method simply deteremines if any child controls exist at /// all, it can enhance performance by avoiding a call to the Count property, /// inherited from the ///class, on the /// property. /// protected bool IsLiteralContent() { return (_occasionalFields != null && _occasionalFields.Controls != null) && (_occasionalFields.Controls.Count == 1) && ((_occasionalFields.Controls[0] is LiteralControl)); } ///Determines if the container holds literal content only. /// When this method returns ////// , the container collection only holds a single literal control. The /// content is then passed to the requesting browser as HTML. /// protected bool IsTrackingViewState { get { return flags[marked]; } } ///Determines if view state changes to the /// ////// are being saved. /// protected virtual void TrackViewState() { if (_viewState != null) _viewState.TrackViewState(); flags.Set(marked); } ///Turns on tracking of view state changes to the control /// so that they can be stored in the ////// object. /// protected virtual void EnsureChildControls() { if (!ChildControlsCreated && !flags[creatingControls]) { flags.Set(creatingControls); try { ResolveAdapter(); if(_adapter != null) { _adapter.CreateChildControls(); } else { CreateChildControls(); } // Only set ChildControlsCreated = true if CreateChildControls() did not throw // an exception (VSWhidbey 465798). ChildControlsCreated = true; } finally { flags.Clear(creatingControls); } } } ///Checks that the control contains child controls; if it does not, it creates /// them. This includes any literal content being parsed as a ////// object. /// Used internally to store a ControlBuilder reference for the control. /// The builder will be used at design-time to help persist all the filtered properties /// of the control. /// internal void SetControlBuilder(ControlBuilder controlBuilder) { RareFieldsEnsured.ControlBuilder = controlBuilder; } ////// protected internal virtual void RemovedControl(Control control) { if (control.OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_NotAllowed)); } if ((_namingContainer != null) && (control._id != null)) { _namingContainer.DirtyNameTable(); } // Controls may need to do their own cleanup. control.UnloadRecursive(false); control._parent = null; control._page = null; control._namingContainer = null; // Don't reset _templateSourceVirtualDirectory on TemplateControl's, because // the path is their own, not their parent. i.e. it doesn't change no matter // where in the tree they end up. if (!(control is TemplateControl)) control._templateSourceVirtualDirectory = null; control._templateControl = null; control.flags.Clear(mustRenderID); control.ClearCachedUniqueIDRecursive(); } internal void SetDesignMode() { flags.Set(designMode); flags.Set(designModeChecked); } ////// /// protected virtual void SetDesignModeState(IDictionary data) { } // Set the delegate to the render method ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public void SetRenderMethodDelegate(RenderMethod renderMethod) { RareFieldsEnsured.RenderMethod = renderMethod; // Make the collection readonly if there are code blocks (ASURT 78810) Controls.SetCollectionReadOnly(SR.Collection_readonly_Codeblocks); } ///Assigns any event handler delegates for the control to match the parameters /// defined in the ///. /// /// bool IDataBindingsAccessor.HasDataBindings { get { return ((RareFields != null) && (RareFields.DataBindings != null) && (RareFields.DataBindings.Count != 0)); } } ///Returns whether the control contains any data binding logic. This method is /// only accessed by RAD designers. ////// /// DataBindingCollection IDataBindingsAccessor.DataBindings { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.DataBindings == null) { rareFields.DataBindings = new DataBindingCollection(); } return rareFields.DataBindings; } } // IParserAccessor interface // A sub-object tag was parsed by the parser; add it to this control. ///Indicates a collection of all data bindings on the control. This property is /// read-only. ////// /// void IParserAccessor.AddParsedSubObject(object obj) { AddParsedSubObject(obj); } internal string SpacerImageUrl { get { EnsureOccasionalFields(); if (_occasionalFields.SpacerImageUrl == null) { _occasionalFields.SpacerImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(WebControl), "Spacer.gif"); } return _occasionalFields.SpacerImageUrl; } } private Control OwnerControl { get { if (RareFields == null) { return null; } return RareFields.OwnerControl; } set { RareFieldsEnsured.OwnerControl = value; } } internal IPostBackDataHandler PostBackDataHandler { get { IPostBackDataHandler pbdh = _adapter as IPostBackDataHandler; if(pbdh != null) return pbdh; pbdh = this as IPostBackDataHandler; return pbdh; } } internal IPostBackEventHandler PostBackEventHandler { get { IPostBackEventHandler pbeh = _adapter as IPostBackEventHandler; if(pbeh != null) return pbeh; pbeh = this as IPostBackEventHandler; return pbeh; } } #if ORCAS internal bool NotVisibleOnPage { get { return flags[notVisibleOnPage]; } set { if(value) { flags.Set(notVisibleOnPage); } else { flags.Clear(notVisibleOnPage); } } } internal int VirtualStartPage { get { return RareFields != null ? RareFields.VirtualStartPage : -1; } set { RareFieldsEnsured.VirtualStartPage = value; } } internal int VirtualEndPage { get { return RareFields != null ? RareFields.VirtualEndPage : -1; } set { RareFieldsEnsured.VirtualEndPage = value; } } #endif #region IControlDesignerAccessor implementation ///Notifies the control that an element, XML or HTML, was parsed, and adds it to /// the control. ///IDictionary IControlDesignerAccessor.UserData { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.ControlDesignerAccessorUserData == null) { rareFields.ControlDesignerAccessorUserData = new HybridDictionary(); } return rareFields.ControlDesignerAccessorUserData; } } /// /// /// IDictionary IControlDesignerAccessor.GetDesignModeState() { return GetDesignModeState(); } ////// /// void IControlDesignerAccessor.SetDesignModeState(IDictionary data) { SetDesignModeState(data); } void IControlDesignerAccessor.SetOwnerControl(Control owner) { if (owner == this) { throw new ArgumentException(SR.GetString(SR.Control_CannotOwnSelf), "owner"); } OwnerControl = owner; _parent = owner.Parent; _page = owner.Page; } #endregion #region IControlBuilderAccessor implementation ////// /// A reference to the ControlBuilder that was used to construct this control (if there was one) /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] ControlBuilder IControlBuilderAccessor.ControlBuilder { get { return RareFields != null ? RareFields.ControlBuilder : null; } } #endregion IControlBuilderAccessor implementation #region IExpressionsAccessor ///bool IExpressionsAccessor.HasExpressions { get { if (RareFields == null) { return false; } ExpressionBindingCollection expressions = RareFields.ExpressionBindings; return ((expressions != null) && (expressions.Count > 0)); } } /// ExpressionBindingCollection IExpressionsAccessor.Expressions { get { ExpressionBindingCollection expressions = RareFieldsEnsured.ExpressionBindings; if (expressions == null) { expressions = new ExpressionBindingCollection(); RareFields.ExpressionBindings = expressions; } return expressions; } } #endregion private sealed class ControlRareFields : IDisposable { internal ControlRareFields() { } public ISite Site; public RenderMethod RenderMethod; // Reference to the templateControl that hosts this control. #if ORCAS public int VirtualStartPage = -1; public int VirtualEndPage = -1; public ContentPager ContentPager; #endif // Reference to the ControlBuilder used to build this control public ControlBuilder ControlBuilder; public DataBindingCollection DataBindings; public Control OwnerControl; public ExpressionBindingCollection ExpressionBindings; public bool RequiredControlState = false; // These fields are only used in the designer so we // keep them here to prevent memory bloat at runtime public IDictionary ControlDesignerAccessorUserData; public IDictionary DesignModeState; public void Dispose() { //do not null out for backwards compat, VSWhidbey 475940 //Site = null; //RenderMethod = null; //DataBindings = null; //OwnerControl = null; //ExpressionBindings = null; ControlBuilder = null; if (OwnerControl != null) { OwnerControl.Dispose(); } ControlDesignerAccessorUserData = null; DesignModeState = null; #if ORCAS ContentPager = null; #endif } } private sealed class OccasionalFields : IDisposable { internal OccasionalFields() { } public string SkinId; // Events public EventHandlerList Events; public IDictionary ControlsViewState; public ControlCollection Controls; public int NamedControlsID; // Only used if we are a naming container. It contains all the controls // in the namespace. public IDictionary NamedControls; public ControlRareFields RareFields; public String UniqueIDPrefix; public string SpacerImageUrl; public void Dispose() { if (Events != null) { Events.Dispose(); Events = null; } if (RareFields != null) { RareFields.Dispose(); } ControlsViewState = null; //do not null out for backwards compat, VSWhidbey 475940 //Controls = null; //NamedControls = null; //UniqueIDPrefix = null; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.UI { using System.Text; using System.ComponentModel; using System; using System.Collections; using System.Collections.Specialized; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; using System.IO; using HttpException = System.Web.HttpException; using System.Web.Configuration; using System.Web.UI.Adapters; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.Util; using System.Web.Hosting; using System.Web.Caching; using System.Security.Permissions; // Delegate used for the compiled template public delegate void RenderMethod(HtmlTextWriter output, Control container); public delegate Control BuildMethod(); // Defines the properties, methods, and events that are shared by all server // controls in the Web Forms page framework. [ Bindable(true), DefaultProperty("ID"), DesignerCategory("Code"), Designer("System.Web.UI.Design.ControlDesigner, " + AssemblyRef.SystemDesign), DesignerSerializer("Microsoft.VisualStudio.Web.WebForms.ControlCodeDomSerializer, " + AssemblyRef.MicrosoftVisualStudioWeb, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + AssemblyRef.SystemDesign), Themeable(false), ToolboxItemFilter("System.Web.UI", ToolboxItemFilterType.Require), ToolboxItemAttribute("System.Web.UI.Design.WebControlToolboxItem, " + AssemblyRef.SystemDesign) ] [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class Control : IComponent, IParserAccessor, IUrlResolutionService, IDataBindingsAccessor, IControlBuilderAccessor, IControlDesignerAccessor, IExpressionsAccessor { internal static readonly object EventDataBinding = new object(); internal static readonly object EventInit = new object(); internal static readonly object EventLoad = new object(); internal static readonly object EventUnload = new object(); internal static readonly object EventPreRender = new object(); private static readonly object EventDisposed = new object(); internal const bool EnableViewStateDefault = true; internal const char ID_SEPARATOR = '$'; private const char ID_RENDER_SEPARATOR = '_'; internal const char LEGACY_ID_SEPARATOR = ':'; private string _id; // allows us to reuse the id variable to store a calculated id w/o polluting the public getter private string _cachedUniqueID; private Control _parent; // fields related to being a container private ControlState _controlState; private StateBag _viewState; // The naming container that this control leaves in. Note that even if // this ctrl is a naming container, it will not point to itself, but to // the naming container that contains it. private Control _namingContainer; internal Page _page; private OccasionalFields _occasionalFields; private TemplateControl _templateControl; // The virtual directory of the Page or UserControl that hosts this control. private VirtualPath _templateSourceVirtualDirectory; internal ControlAdapter _adapter; // const masks into the BitVector32 private const int idNotCalculated = 0x00000001; private const int marked = 0x00000002; private const int disableViewState = 0x00000004; private const int controlsCreated = 0x00000008; private const int invisible = 0x00000010; private const int visibleDirty = 0x00000020; private const int idNotRequired = 0x00000040; private const int isNamingContainer = 0x00000080; private const int creatingControls = 0x00000100; private const int notVisibleOnPage = 0x00000200; private const int themeApplied = 0x00000400; private const int mustRenderID = 0x00000800; private const int disableTheming = 0x00001000; private const int enableThemingSet = 0x00002000; private const int styleSheetApplied = 0x00004000; private const int controlAdapterResolved = 0x00008000; private const int designMode = 0x00010000; private const int designModeChecked = 0x00020000; private const int disableChildControlState = 0x00040000; internal const int isWebControlDisabled = 0x00080000; private const int controlStateApplied = 0x00100000; private const int useGeneratedID = 0x00200000; #pragma warning disable 0649 internal SimpleBitVector32 flags; #pragma warning restore 0649 private const string automaticIDPrefix = "ctl"; private const string automaticLegacyIDPrefix = "_ctl"; private const int automaticIDCount = 128; private static readonly string[] automaticIDs = new string [automaticIDCount] { "ctl00", "ctl01", "ctl02", "ctl03", "ctl04", "ctl05", "ctl06", "ctl07", "ctl08", "ctl09", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15", "ctl16", "ctl17", "ctl18", "ctl19", "ctl20", "ctl21", "ctl22", "ctl23", "ctl24", "ctl25", "ctl26", "ctl27", "ctl28", "ctl29", "ctl30", "ctl31", "ctl32", "ctl33", "ctl34", "ctl35", "ctl36", "ctl37", "ctl38", "ctl39", "ctl40", "ctl41", "ctl42", "ctl43", "ctl44", "ctl45", "ctl46", "ctl47", "ctl48", "ctl49", "ctl50", "ctl51", "ctl52", "ctl53", "ctl54", "ctl55", "ctl56", "ctl57", "ctl58", "ctl59", "ctl60", "ctl61", "ctl62", "ctl63", "ctl64", "ctl65", "ctl66", "ctl67", "ctl68", "ctl69", "ctl70", "ctl71", "ctl72", "ctl73", "ctl74", "ctl75", "ctl76", "ctl77", "ctl78", "ctl79", "ctl80", "ctl81", "ctl82", "ctl83", "ctl84", "ctl85", "ctl86", "ctl87", "ctl88", "ctl89", "ctl90", "ctl91", "ctl92", "ctl93", "ctl94", "ctl95", "ctl96", "ctl97", "ctl98", "ctl99", "ctl100", "ctl101", "ctl102", "ctl103", "ctl104", "ctl105", "ctl106", "ctl107", "ctl108", "ctl109", "ctl110", "ctl111", "ctl112", "ctl113", "ctl114", "ctl115", "ctl116", "ctl117", "ctl118", "ctl119", "ctl120", "ctl121", "ctl122", "ctl123", "ctl124", "ctl125", "ctl126", "ctl127" }; ////// public Control() { if (this is INamingContainer) flags.Set(isNamingContainer); } ///Initializes a new instance of the ///class. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_ClientID) ] public virtual string ClientID { // This property is required to render a unique client-friendly id. get { // Ensure that ID is set. The assumption being made is that the caller // is likely to use the client ID in script, and to support that the // control should render out an ID attribute EnsureID(); string uniqueID = UniqueID; if(uniqueID != null && uniqueID.IndexOf(IdSeparator) >= 0) { return uniqueID.Replace(IdSeparator, ID_RENDER_SEPARATOR); } return uniqueID; } } protected char ClientIDSeparator { get { return ID_RENDER_SEPARATOR; } } ///Indicates the control identifier generated by the ASP.NET framework. This /// property is read-only. ////// [ WebSysDescription(SR.Control_OnDisposed) ] public event EventHandler Disposed { add { Events.AddHandler(EventDisposed, value); } remove { Events.RemoveHandler(EventDisposed, value); } } ///[To be supplied.] ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] protected internal virtual HttpContext Context { // Request context containing the intrinsics get { Page page = Page; if(page != null) { return page.Context; } return HttpContext.Current; } } protected virtual ControlAdapter ResolveAdapter() { if(flags[controlAdapterResolved]) { return _adapter; } if (DesignMode) { flags.Set(controlAdapterResolved); return null; } HttpContext context = Context; if (context != null) { _adapter = context.Request.Browser.GetAdapter(this); } flags.Set(controlAdapterResolved); return _adapter; } ///Gets the ///object of the current Web request. If /// the control's context is , this will be the context of the /// control's parent, unless the parent control's context is . /// If this is the case, this will be equal to the HttpContext property. /// protected ControlAdapter Adapter { get { if(flags[controlAdapterResolved]) { return _adapter; } _adapter = ResolveAdapter(); flags.Set(controlAdapterResolved); return _adapter; } } ///Indicates the list of event handler delegates for the control. This property /// is read-only. ////// Indicates whether a control is being used in the context of a design surface. /// protected internal bool DesignMode { get { if(!flags[designModeChecked]) { Page page = Page; if(page != null ) { if(page.GetDesignModeInternal()) { flags.Set(designMode); } else { flags.Clear(designMode); } } else { if(Site != null) { if(Site.DesignMode) { flags.Set(designMode); } else { flags.Clear(designMode); } } else if (Parent != null) { if(Parent.DesignMode) { flags.Set(designMode); } // VSWhidbey 535747: If Page, Site and Parent are all null, do not change the // designMode flag since it might had been previously set by the controlBuilder. // This does not affect runtime since designMode is by-default false. /* else { flags.Clear(designMode); } */ } } flags.Set(designModeChecked); } return flags[designMode]; } } // Helper function to call validateEvent. internal void ValidateEvent(string uniqueID) { ValidateEvent(uniqueID, String.Empty); } // Helper function to call validateEvent. internal void ValidateEvent(string uniqueID, string eventArgument) { if (Page != null && SupportsEventValidation) { Page.ClientScript.ValidateEvent(uniqueID, eventArgument); } } // Indicates whether the control supports event validation // By default, all web controls in System.Web assembly supports it but not custom controls. private bool SupportsEventValidation { get { return SupportsEventValidationAttribute.SupportsEventValidation(this.GetType()); } } ////// protected EventHandlerList Events { get { EnsureOccasionalFields(); if(_occasionalFields.Events == null) { _occasionalFields.Events = new EventHandlerList(); } return _occasionalFields.Events; } } protected bool HasEvents() { return ((_occasionalFields != null) && (_occasionalFields.Events != null)); } ///Indicates the list of event handler delegates for the control. This property /// is read-only. ////// [ ParenthesizePropertyName(true), MergableProperty(false), Filterable(false), Themeable(false), WebSysDescription(SR.Control_ID) ] public virtual string ID { get { if (!flags[idNotCalculated] && !flags[mustRenderID]) { return null; } return _id; } set { // allow the id to be unset if (value != null && value.Length == 0) value = null; string oldID = _id; _id = value; ClearCachedUniqueIDRecursive(); flags.Set(idNotCalculated); flags.Clear(useGeneratedID); // Update the ID in the naming container if ((_namingContainer != null) && (oldID != null)) { _namingContainer.DirtyNameTable(); } } } ///Gets or sets the identifier for the control. Setting the /// property on a control allows programmatic access to the control's properties. If /// this property is not specified on a control, either declaratively or /// programmatically, then you cannot write event handlers and the like for the control. ////// [ Browsable(false), DefaultValue(true), Themeable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_EnableTheming) ] public virtual bool EnableTheming { get { if (flags[enableThemingSet]) { return !flags[disableTheming]; } if (Parent != null) { return Parent.EnableTheming; } return !flags[disableTheming]; } set { if ((_controlState >= ControlState.FrameworkInitialized) && !DesignMode) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePreInitOrAddToControls, "EnableTheming")); } if(!value) { flags.Set(disableTheming); } else { flags.Clear(disableTheming); } flags.Set(enableThemingSet); } } // Serialzie the value if it's set explicitely. internal bool ShouldSerializeEnableTheming() { return flags[enableThemingSet];; } internal bool IsBindingContainer { get { return this is INamingContainer && !(this is INonBindingContainer); } } protected internal bool IsChildControlStateCleared { get { return flags[disableChildControlState]; } } ///Gets and sets a value indicating whether theme is enabled. ////// [ Browsable(false), DefaultValue(""), Filterable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_SkinId), ] public virtual string SkinID { get { if(_occasionalFields != null) { return _occasionalFields.SkinId == null ? String.Empty : _occasionalFields.SkinId; } return String.Empty; } set { if (!DesignMode) { if (flags[styleSheetApplied]) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforeStyleSheetApplied, "SkinId")); } if (_controlState >= ControlState.FrameworkInitialized) { throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePreInitOrAddToControls, "SkinId")); } } EnsureOccasionalFields(); _occasionalFields.SkinId = value; } } private ControlRareFields RareFieldsEnsured { get { EnsureOccasionalFields(); ControlRareFields rareFields = _occasionalFields.RareFields; if(rareFields == null) { rareFields = new ControlRareFields(); _occasionalFields.RareFields = rareFields; } return rareFields; } } private ControlRareFields RareFields { get { if(_occasionalFields != null) { return _occasionalFields.RareFields; } return null; } } private void EnsureOccasionalFields() { if(_occasionalFields == null) { _occasionalFields = new OccasionalFields(); } } ///Gets and sets the skinID of the control. ////// [ DefaultValue(EnableViewStateDefault), Themeable(false), WebCategory("Behavior"), WebSysDescription(SR.Control_MaintainState) ] public virtual bool EnableViewState { get { return !flags[disableViewState]; } set { SetEnableViewStateInternal(value); } } internal void SetEnableViewStateInternal(bool value) { if (!value) flags.Set(disableViewState); else flags.Clear(disableViewState); } ////// Gets or sets a value indicating whether the control should maintain its view /// state, and the view state of any child control in contains, when the current /// page request ends. /// ////// Gets a value indicating whether the control is maintaining its view /// state, when the current page request ends by looking at its own EnableViewState /// value, and the value for all its parents. /// protected internal bool IsViewStateEnabled { get { Control current = this; while (current != null) { if (current.EnableViewState == false) { return false; } current = current.Parent; } return true; } } ////// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_NamingContainer) ] public virtual Control NamingContainer { get { if (_namingContainer == null) { if (Parent != null) { // Search for the closest naming container in the tree if (Parent.flags[isNamingContainer]) _namingContainer = Parent; else _namingContainer = Parent.NamingContainer; } } return _namingContainer; } } ///Gets the reference to the current control's naming container. ////// /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never) ] public Control BindingContainer { get { Control bindingContainer = NamingContainer; while (bindingContainer is INonBindingContainer) { bindingContainer = bindingContainer.BindingContainer; } return bindingContainer; } } ///Returns the databinding container of this control. In most cases, /// this is the same as the NamingContainer. But when using LoadTemplate(), /// we get into a situation where that is not the case (ASURT 94138) /// The behavior is different than V1 that Usercontrol.BindingContainer is no /// longer the UserControl but the control contains it. The behavior is consistent /// with LoadTemplate() case. ////// /// VSWhidbey 80467: Need to adapt id separator. /// protected char IdSeparator { get { if (Page != null) { return Page.IdSeparator; } return IdSeparatorFromConfig; } } // VSWhidbey 475945: Use the old id separator if configured internal char IdSeparatorFromConfig { get { return ((EnableLegacyRendering) ? LEGACY_ID_SEPARATOR : ID_SEPARATOR); } } // VSWhidbey 244374: Allow controls to opt into loading view state by ID instead of index (perf hit) protected bool LoadViewStateByID { get { return ViewStateModeByIdAttribute.IsEnabled(GetType()); } } ////// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Page) ] public virtual Page Page { get { if (_page == null) { if (Parent != null) { _page = Parent.Page; } } return _page; } set { if (OwnerControl != null) { throw new InvalidOperationException(); } // This is necessary because we need to set the page in generated // code before controls are added to the tree (ASURT 75330) Debug.Assert(_page == null); Debug.Assert(Parent == null || Parent.Page == null); _page = value; } } // VSWhidbey 244999 internal virtual bool IsReloadable { get { return false; } } // DevDiv 33149, 43258: A backward compat. switch for Everett rendering internal bool EnableLegacyRendering { get { Page page = Page; if (page != null) { return (page.XhtmlConformanceMode == XhtmlConformanceMode.Legacy); } else if (DesignMode || Adapter != null) { return false; } else { return (GetXhtmlConformanceSection().Mode == XhtmlConformanceMode.Legacy); } } } internal XhtmlConformanceSection GetXhtmlConformanceSection() { HttpContext context = Context; XhtmlConformanceSection xhtmlConformanceSection; if (context != null) { // if context is available, use the most efficient way to get the section xhtmlConformanceSection = RuntimeConfig.GetConfig(context).XhtmlConformance; } else { xhtmlConformanceSection = RuntimeConfig.GetConfig().XhtmlConformance; } Debug.Assert(xhtmlConformanceSection != null); return xhtmlConformanceSection; } #if ORCAS ///Gets the ///object that contains the /// current control. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Pager) ] public virtual ContentPager ContentPager { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.ContentPager == null) { if (Parent != null) { rareFields.ContentPager = Parent.ContentPager; } } return rareFields.ContentPager; } set { RareFieldsEnsured.ContentPager = value; } } #endif ///Gets the ///object that /// paginates the current control. /// internal virtual TemplateControl GetTemplateControl() { if(_templateControl == null) { if (Parent != null) { _templateControl = Parent.GetTemplateControl(); } } return _templateControl; } ///Gets the reference to the ////// that hosts the control. /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateControl) ] public TemplateControl TemplateControl { get { return GetTemplateControl(); } [EditorBrowsable(EditorBrowsableState.Never)] set { // This setter is necessary so that controls inside templates are based on // hosting pages not where the templates are used. _templateControl = value; } } /* * Determine whether this control is a descendent of the passed in control */ internal bool IsDescendentOf(Control ancestor) { Control current = this; while (current != ancestor && current.Parent != null) { current = current.Parent; } return (current == ancestor); } ///Gets the reference to the ////// that hosts the control. /// [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Parent) ] public virtual Control Parent { get { return _parent; } } internal bool IsParentedToUpdatePanel { get { Control parent = Parent; while (parent != null) { if (parent is IUpdatePanel) { return true; } parent = parent.Parent; } return false; } } ///Gets the current control's parent control in the UI hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateSourceDirectory) ] public virtual string TemplateSourceDirectory { get { if (TemplateControlVirtualDirectory == null) return String.Empty; return TemplateControlVirtualDirectory.VirtualPathStringNoTrailingSlash; } } ///Gets the virtual directory of the Page or UserControl that contains this control. ////// [ Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_TemplateSourceDirectory) ] public string AppRelativeTemplateSourceDirectory { get { return VirtualPath.GetAppRelativeVirtualPathStringOrEmpty(TemplateControlVirtualDirectory); } [EditorBrowsable(EditorBrowsableState.Never)] set { // This setter is necessary so that skins are based on hosting skin file. this.TemplateControlVirtualDirectory = VirtualPath.CreateNonRelativeAllowNull(value); } } internal VirtualPath TemplateControlVirtualDirectory { get { if (_templateSourceVirtualDirectory != null) return _templateSourceVirtualDirectory; TemplateControl control = TemplateControl; if (control == null) { HttpContext context = Context; if (context != null) { _templateSourceVirtualDirectory = context.Request.CurrentExecutionFilePathObject.Parent; } return _templateSourceVirtualDirectory; } // Prevent recursion if this is the TemplateControl if (control != this) { _templateSourceVirtualDirectory = control.TemplateControlVirtualDirectory; } return _templateSourceVirtualDirectory; } set { // This setter is necessary so that skins are based on hosting skin file. _templateSourceVirtualDirectory = value; } } internal ControlState ControlState { get { return _controlState; } set { _controlState = value; } } ///Gets the virtual directory of the Page or UserControl that contains this control. /// Unlike TemplateSourceDirectory, this returns an app relative path (e.g. "~/sub") ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Advanced), WebSysDescription(SR.Control_Site) ] public ISite Site { get { if (OwnerControl != null) { return OwnerControl.Site; } if (RareFields != null) { return RareFields.Site; } return null; } set { if (OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_SiteNotAllowed)); } RareFieldsEnsured.Site = value; flags.Clear(designModeChecked); } } ///Indicates the site information for the control. ////// [ Bindable(true), DefaultValue(true), WebCategory("Behavior"), WebSysDescription(SR.Control_Visible) ] public virtual bool Visible { get { if (flags[invisible]) return false; #if ORCAS if (NotVisibleOnPage) return false; #endif else if ((_parent != null) && !DesignMode) return _parent.Visible; else return true; } set { if (flags[marked]) { bool visible = !flags[invisible]; if (visible != value) { flags.Set(visibleDirty); } } if(!value) { flags.Set(invisible); } else { flags.Clear(invisible); } } } #if ORCAS internal bool ExplicitlyInvisible { get { return flags[invisible]; } } #endif ////// Gets or sets a value that indicates whether a control should be rendered on /// the page. /// ////// Do not remove or change the signature. It is called via reflection. /// This allows for correct serialization, since Visible is implemented as a /// recursive property. /// private void ResetVisible() { Visible = true; } ////// Do not remove or change the signature. It is called via reflection. /// This allows for correct serialization, since Visible is implemented as a /// recursive property. /// private bool ShouldSerializeVisible() { return flags[invisible]; } ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_UniqueID) ] public virtual string UniqueID { get { if (_cachedUniqueID != null) { return _cachedUniqueID; } Control namingContainer = NamingContainer; if (namingContainer != null) { // if the ID is null at this point, we need to have one created and the control added to the // naming container. if (_id == null) { GenerateAutomaticID(); } if (Page == namingContainer) { _cachedUniqueID = _id; } else { string uniqueIDPrefix = namingContainer.GetUniqueIDPrefix(); if (uniqueIDPrefix.Length == 0) { // In this case, it is probably a naming container that is not sited, so we don't want to cache it return _id; } else { _cachedUniqueID = uniqueIDPrefix + _id; } } return _cachedUniqueID; } else { // no naming container return _id; } } } #if SHIPPINGADAPTERS // Used by adapters in delegating rendering (e.g., a Button for a LinkButton for scriptless devices). // The UniqueID of the new control has to be set to match the UniqueID of the original. internal void SetUniqueID(string val) { _cachedUniqueID = val; } #endif ///Gets the unique, hierarchically-qualified identifier for /// a control. This is different from the ID property, in that the fully-qualified /// identifier includes the identifier for the control's naming container. ////// [ WebCategory("Data"), WebSysDescription(SR.Control_OnDataBind) ] public event EventHandler DataBinding { add { Events.AddHandler(EventDataBinding, value); } remove { Events.RemoveHandler(EventDataBinding, value); } } ///Occurs when the control binds to a data source. Notifies the control to perform any data binding during this event. ////// [ WebSysDescription(SR.Control_OnInit) ] public event EventHandler Init { add { Events.AddHandler(EventInit, value); } remove { Events.RemoveHandler(EventInit, value); } } ///Occurs when the control is initialized, the first step in the page lifecycle. Controls should /// perform any initialization steps that are required to create and set up an /// instantiation. ////// [ WebSysDescription(SR.Control_OnLoad) ] public event EventHandler Load { add { Events.AddHandler(EventLoad, value); } remove { Events.RemoveHandler(EventLoad, value); } } ///Occurs when the control is loaded to the ///object. Notifies the control to perform any steps that /// need to occur on each page request. /// [ WebSysDescription(SR.Control_OnPreRender) ] public event EventHandler PreRender { add { Events.AddHandler(EventPreRender, value); } remove { Events.RemoveHandler(EventPreRender, value); } } ///Occurs when the control is about to render. Controls /// should perform any pre-rendering steps necessary before saving view state and /// rendering content to the ///object. /// [ WebSysDescription(SR.Control_OnUnload) ] public event EventHandler Unload { add { Events.AddHandler(EventUnload, value); } remove { Events.RemoveHandler(EventUnload, value); } } ///Occurs when the control is unloaded from memory. Controls should perform any /// final cleanup before this instance of it is ////// [ EditorBrowsable(EditorBrowsableState.Advanced), ] public virtual void ApplyStyleSheetSkin(Page page) { // Nothing to do if the control is not in a Page. if (page == null) { return; } // Only apply stylesheet if not already applied. if (flags[styleSheetApplied]) { throw new InvalidOperationException(SR.GetString(SR.StyleSheetAreadyAppliedOnControl)); } if (page.ApplyControlStyleSheet(this)) { flags.Set(styleSheetApplied); } } ///Apply stylesheet skin on the control. ////// private void ApplySkin(Page page) { if (page == null) { throw new ArgumentNullException("page"); } if (flags[themeApplied]) { return; } if (ThemeableAttribute.IsTypeThemeable(this.GetType())) { page.ApplyControlSkin(this); flags.Set(themeApplied); } } ///Apply theme on the control. ////// protected virtual void OnDataBinding(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventDataBinding] as EventHandler; if(handler != null) { handler(this, e); } } } ///Raises the ///event. This /// notifies a control to perform any data binding logic that is associated with it. /// public virtual void DataBind() { DataBind(true); } ///Causes data binding to occur on the invoked control and all of its child /// controls. ////// protected virtual void DataBind(bool raiseOnDataBinding) { bool inDataBind = false; if (IsBindingContainer) { bool foundDataItem; object dataItem = DataBinder.GetDataItem(this, out foundDataItem); if (foundDataItem && (Page != null)) { Page.PushDataBindingContext(dataItem); inDataBind = true; } } try { if (raiseOnDataBinding) { // Do our own databinding OnDataBinding(EventArgs.Empty); } // Do all of our children's databinding DataBindChildren(); } finally { if (inDataBind) { Page.PopDataBindingContext(); } } } ///Causes the invoked controls' context to be pushed on the stack, /// then conditionally call OnDataBinging on the invoked control, and databind all of its child /// controls. A control would call this with false if it overrides DataBind without calling /// Control.DataBind, but still wants to be an IDataItemContainer. FormView and DetailsView /// are good examples of this. ////// protected virtual void DataBindChildren() { if (HasControls()) { EnsureOccasionalFields(); string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); try { try { int controlCount = _occasionalFields.Controls.Count; for (int i=0; i < controlCount; i++) _occasionalFields.Controls[i].DataBind(); } finally { _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } } catch { throw; } } } internal void PreventAutoID() { // controls that are also naming containers must always get an id if (flags[isNamingContainer] == false) { flags.Set(idNotRequired); } } ///Causes data binding to occur on all of the child controls. ////// protected virtual void AddParsedSubObject(object obj) { Control control = obj as Control; if (control != null) { Controls.Add(control); } } private void UpdateNamingContainer(Control namingContainer) { // Remove the cached uniqueID if the control already had a namingcontainer // and the namingcontainer is changed. if (_namingContainer != null && _namingContainer != namingContainer) { ClearCachedUniqueIDRecursive(); } _namingContainer = namingContainer; } private void ClearCachedUniqueIDRecursive() { _cachedUniqueID = null; if (_occasionalFields != null) { _occasionalFields.UniqueIDPrefix = null; if (_occasionalFields.Controls != null) { int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].ClearCachedUniqueIDRecursive(); } } } } protected void EnsureID() { if (_namingContainer != null) { if (_id == null) { GenerateAutomaticID(); } flags.Set(mustRenderID); } } private void GenerateAutomaticID() { Debug.Assert(_namingContainer != null); Debug.Assert(_id == null); // Remember that a generated ID is used for this control. flags.Set(useGeneratedID); // Calculate the automatic ID. For performance and memory reasons // we look up a static table entry if possible _namingContainer.EnsureOccasionalFields(); int idNo = _namingContainer._occasionalFields.NamedControlsID++; if (EnableLegacyRendering) { // VSWhidbey 517118 _id = automaticLegacyIDPrefix + idNo.ToString(NumberFormatInfo.InvariantInfo); } else { if (idNo < automaticIDCount) { _id = automaticIDs[idNo]; } else { _id = automaticIDPrefix + idNo.ToString(NumberFormatInfo.InvariantInfo); } } _namingContainer.DirtyNameTable(); } internal virtual string GetUniqueIDPrefix() { EnsureOccasionalFields(); if (_occasionalFields.UniqueIDPrefix == null) { string uniqueID = UniqueID; if (!String.IsNullOrEmpty(uniqueID)) { _occasionalFields.UniqueIDPrefix = uniqueID + IdSeparator; } else { _occasionalFields.UniqueIDPrefix = String.Empty; } } return _occasionalFields.UniqueIDPrefix; } ///Notifies the control that an element, XML or HTML, was parsed, and adds it to /// the control. ////// protected internal virtual void OnInit(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventInit] as EventHandler; if(handler != null) { handler(this, e); } } } internal virtual void InitRecursive(Control namingContainer) { ResolveAdapter(); if (_occasionalFields != null && _occasionalFields.Controls != null) { if (flags[isNamingContainer]) { namingContainer = this; } string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { Control control = _occasionalFields.Controls[i]; // Propagate the page and namingContainer control.UpdateNamingContainer(namingContainer); if ((control._id == null) && (namingContainer != null) && !control.flags[idNotRequired]) { control.GenerateAutomaticID(); } control._page = Page; control.InitRecursive(namingContainer); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } // Only make the actual call if it hasn't already happened (ASURT 111303) if (_controlState < ControlState.Initialized) { _controlState = ControlState.ChildrenInitialized; // framework also initialized if ((Page != null) && !DesignMode) { if (Page.ContainsTheme && EnableTheming) { ApplySkin(Page); } } if (_adapter != null) { _adapter.OnInit(EventArgs.Empty); } else { OnInit(EventArgs.Empty); } _controlState = ControlState.Initialized; } // track all subsequent state changes TrackViewState(); #if DEBUG ControlInvariant(); #endif } #if DEBUG ///Raises the ///event. This notifies the control to perform /// any steps necessary for its creation on a page request. /// internal void ControlInvariant() { // If the control is initialized, the naming container and page should have been pushed in if (_controlState >= ControlState.Initialized) { if (DesignMode) { // Top-level UserControls do not have a page or a naming container in the designer // hence the special casing. Debug.Assert((_namingContainer != null) || (this is Page) || (this is UserControl)); // } else { if (!(this is Page)) { Debug.Assert(_namingContainer != null); } Debug.Assert(Page != null); } } // If naming container is set and the name table exists, the ID should exist in it. if(_namingContainer != null && _namingContainer._occasionalFields != null && _namingContainer._occasionalFields.NamedControls != null && _id != null) { Debug.Assert(_namingContainer._occasionalFields.NamedControls.Contains(_id)); } } // Collect some statistic about the number of controls with occasional and // rare fields. internal void GetRareFieldStatistics(ref int totalControls, ref int withOccasionalFields, ref int withRareFields) { totalControls++; if (_occasionalFields != null) { withOccasionalFields++; if (_occasionalFields.RareFields != null) withRareFields++; // No children: we're done if (_occasionalFields.Controls == null) return; int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { Control control = _occasionalFields.Controls[i]; control.GetRareFieldStatistics(ref totalControls, ref withOccasionalFields, ref withRareFields); } } } #endif protected void ClearChildState() { ClearChildControlState(); ClearChildViewState(); } protected void ClearChildControlState() { //VSWhidbey 242621 to be consistent with ClearChildViewState, ignore calls before and during Init if (ControlState < ControlState.Initialized) { return; } flags.Set(disableChildControlState); if (Page != null) { Page.RegisterRequiresClearChildControlState(this); } } ///This should be used to assert internal state about the control ////// protected void ClearChildViewState() { if(_occasionalFields != null) { _occasionalFields.ControlsViewState = null; } } ///Deletes the view state information for all of the current control's child /// controls. ////// protected bool HasChildViewState { get { return ((_occasionalFields != null) && (_occasionalFields.ControlsViewState != null) && (_occasionalFields.ControlsViewState.Count > 0)); } } ///Indicates whether the current control's children have any saved view state /// information. This property is read-only. ////// Sets initial focus on the control /// public virtual void Focus() { Page.SetFocus(this); } internal void LoadControlStateInternal(object savedStateObj) { // Do not load the control state if it has been applied. if (flags[controlStateApplied]) { return; } flags.Set(controlStateApplied); Pair savedState = (Pair)savedStateObj; if (savedState == null) { return; } Page page = Page; if (page != null && !page.ShouldLoadControlState(this)) { return; } // VSWhidbey160650: Only call LoadControlState with non null savedState if (savedState.First != null) { LoadControlState(savedState.First); } // VSWhidbey356804: Only call LoadAdapterControlState with non null savedState if (_adapter == null || savedState.Second == null) { return; } _adapter.LoadAdapterControlState(savedState.Second); } ////// Load the control state, which is the essential state information needed even if view state is disabled. /// protected internal virtual void LoadControlState(object savedState) { } ////// protected virtual void LoadViewState(object savedState) { if (savedState != null) { ViewState.LoadViewState(savedState); // Load values cached out of view state object visible = ViewState["Visible"]; if (visible != null) { if(!(bool)visible) { flags.Set(invisible); } else { flags.Clear(invisible); } flags.Set(visibleDirty); } } } internal void LoadViewStateRecursive(object savedState) { // nothing to do if we have no state if (savedState == null || flags[disableViewState]) return; if (Page != null && Page.IsPostBack) { object controlState = null; object adapterState = null; ArrayList childState = null; Pair allSavedState = savedState as Pair; if (allSavedState != null) { controlState = allSavedState.First; childState = (ArrayList)allSavedState.Second; } else { Debug.Assert(savedState is Triplet); Triplet t = (Triplet)savedState; controlState = t.First; adapterState = t.Second; childState = (ArrayList)t.Third; } try { if ((adapterState != null) && (_adapter != null)) { _adapter.LoadAdapterViewState(adapterState); } if (controlState != null) { LoadViewState(controlState); } if (childState != null) { if (LoadViewStateByID) { LoadChildViewStateByID(childState); } else { LoadChildViewStateByIndex(childState); } } } catch (InvalidCastException) { // catch all viewstate loading problems with casts. They are most likely changed control trees. throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts)); } catch (IndexOutOfRangeException) { // catch all viewstate loading problems with indeces. They are most likely changed control trees. throw new HttpException(SR.GetString(SR.Controls_Cant_Change_Between_Posts)); } } _controlState = ControlState.ViewStateLoaded; } internal void LoadChildViewStateByID(ArrayList childState) { int childStateCount = childState.Count; for (int i = 0; i < childStateCount; i += 2) { // first element is index or ID of control with state and the // next element is state of the control string controlId = (string)childState[i]; object state = childState[i + 1]; Control childControl = FindControl(controlId); if (childControl != null) { childControl.LoadViewStateRecursive(state); } else { // couldn't find a control for this state blob, save it for later EnsureOccasionalFields(); if (_occasionalFields.ControlsViewState == null) { _occasionalFields.ControlsViewState = new Hashtable(); } _occasionalFields.ControlsViewState[controlId] = state; } } } internal void LoadChildViewStateByIndex(ArrayList childState) { ControlCollection ctrlColl = Controls; int ctrlCount = ctrlColl.Count; int childStateCount = childState.Count; for (int i = 0; i < childStateCount; i += 2) { // first element is index of control with state and the // next element is state of the control int controlIndex = (int)childState[i]; object state = childState[i + 1]; if (controlIndex < ctrlCount) { // we have a control for this state blob ctrlColl[controlIndex].LoadViewStateRecursive(state); } else { // couldn't find a control for this state blob, save it for later EnsureOccasionalFields(); if (_occasionalFields.ControlsViewState == null) { _occasionalFields.ControlsViewState = new Hashtable(); } _occasionalFields.ControlsViewState[controlIndex] = state; } } } /// /// Figure out if a path is physical or virtual. This is useful because a number of our controls /// accept either type of path for the same attribute. /// internal void ResolvePhysicalOrVirtualPath(string path, out VirtualPath virtualPath, out string physicalPath) { if (System.Web.Util.UrlPath.IsAbsolutePhysicalPath(path)) { physicalPath = path; virtualPath = null; } else { physicalPath = null; // It could be relative, so resolve it virtualPath = TemplateControlVirtualDirectory.Combine(VirtualPath.Create(path)); } } ///Restores the view state information from a previous page /// request that was saved by the Control.SavedState method. ////// protected internal string MapPathSecure(string virtualPath) { if (String.IsNullOrEmpty(virtualPath)) { throw new ArgumentNullException("virtualPath", SR.GetString(SR.VirtualPath_Length_Zero)); } string physicalPath; VirtualPath virtualPathObject; ResolvePhysicalOrVirtualPath(virtualPath, out virtualPathObject, out physicalPath); if (physicalPath == null) { physicalPath = virtualPathObject.MapPathInternal(TemplateControlVirtualDirectory, true /*allowCrossAppMapping*/); } // Security check HttpRuntime.CheckFilePermission(physicalPath); return physicalPath; } ////// This function takes a virtual path, that is a relative or root relative URL without a protocol. /// It returns the mapped physcial file name relative to the template source. It throws an exception if /// there is insufficient security access to read or investigate the mapped result. This should be used /// by controls that can read files and live in fully trusted DLLs such as System.Web.dll to prevent /// security issues. The exception thrown does not give away information about the mapping. For absolute /// physical paths, this function checks permission /// ////// protected internal Stream OpenFile(string path) { string physicalPath = null; VirtualFile vfile = null; // Need to Trim it since MapPath no longer allows trailing space (VSWhidbey 441210) path = path.Trim(); if (UrlPath.IsAbsolutePhysicalPath(path)) { // Absolute physical path physicalPath = path; } else { vfile = HostingEnvironment.VirtualPathProvider.GetFile(path); MapPathBasedVirtualFile mapPathVFile = vfile as MapPathBasedVirtualFile; if (mapPathVFile != null) { physicalPath = mapPathVFile.PhysicalPath; } } // If we got a physical path, make sure the user has access to it if (physicalPath != null) { HttpRuntime.CheckFilePermission(physicalPath); } if (vfile != null) { return vfile.Open(); } else { return new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read); } } /// /// Open a stream from either a virtual or physical path, and if possible get a CacheDependency /// for the resulting Stream. /// internal Stream OpenFileAndGetDependency(VirtualPath virtualPath, string physicalPath, out CacheDependency dependency) { // Only one of the paths should be non-null Debug.Assert((virtualPath == null) != (physicalPath == null)); // If we got a virtual path, and we're using the default VPP, call MapPath if (physicalPath == null && HostingEnvironment.UsingMapPathBasedVirtualPathProvider) { physicalPath = virtualPath.MapPathInternal(TemplateControlVirtualDirectory, true /*allowCrossAppMapping*/); } Stream stream; if (physicalPath != null) { // Security check HttpRuntime.CheckFilePermission(physicalPath); // Work directly with the physical file, bypassing the VPP stream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read); dependency = new CacheDependency(0, physicalPath); } else { // It's non file system based, so go though the VirtualPathProvider stream = virtualPath.OpenFile(); dependency = VirtualPathProvider.GetCacheDependency(virtualPath); } return stream; } ////// This function takes a virtual path, that is a relative or root relative URL without a protocol. /// It can also take a physical path, either local (c:\) or UNC. /// It returns a stream used to read to contents of the file. It throws an exception if /// there is insufficient security access to read or investigate the mapped result. This should be used /// by controls that can read files and live in fully trusted DLLs such as System.Web.dll to prevent /// security issues. The exception thrown does not give away information about the mapping. For absolute /// physical paths, this function checks permission /// ////// protected internal virtual void OnLoad(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventLoad] as EventHandler; if(handler != null) { handler(this, e); } } } internal virtual void LoadRecursive() { // Only make the actual call if it hasn't already happened (ASURT 111303) if (_controlState < ControlState.Loaded) { if(_adapter != null) { _adapter.OnLoad(EventArgs.Empty); } else { OnLoad(EventArgs.Empty); } } // Call Load on all our children if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].LoadRecursive(); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } if (_controlState < ControlState.Loaded) _controlState = ControlState.Loaded; } ///Raises the ////// event. This notifies the control that it should perform any work that needs to /// occur for each page request. /// protected internal virtual void OnPreRender(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventPreRender] as EventHandler; if (handler != null) { handler(this, e); } } } internal virtual void PreRenderRecursiveInternal() { // Call Visible property and cache value in !flags[invisible] to allow Visible to be overridden. // This avoids unnecessary virtual property calls in SaveViewState and Render. bool visible = Visible; if(!visible) { flags.Set(invisible); } else { flags.Clear(invisible); EnsureChildControls(); if(_adapter != null) { _adapter.OnPreRender(EventArgs.Empty); } else { OnPreRender(EventArgs.Empty); } if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i=0; i < controlCount; i++) { _occasionalFields.Controls[i].PreRenderRecursiveInternal(); } _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } } _controlState = ControlState.PreRendered; } internal int EstimateStateSize(object state) { if(state == null) { return 0; } return Util.SerializeWithAssert(new ObjectStateFormatter(), state).Length; } /* * Walk the tree and fill in profile information */ ///Raises the ///event. This method uses event arguments /// to pass the event data to the control. /// /// protected void BuildProfileTree(string parentId, bool calcViewState) { // estimate the viewstate size. calcViewState = calcViewState && (!flags[disableViewState]); int viewstatesize; if (calcViewState) viewstatesize = EstimateStateSize(SaveViewState()); else viewstatesize = 0; int controlstatesize = 0; if(Page != null && Page._registeredControlsRequiringControlState != null && Page._registeredControlsRequiringControlState.Contains(this)) { controlstatesize = EstimateStateSize(SaveControlStateInternal()); } // give it all to the profiler Page.Trace.AddNewControl(UniqueID, parentId, this.GetType().FullName, viewstatesize, controlstatesize); if (_occasionalFields != null && _occasionalFields.Controls != null) { int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) { _occasionalFields.Controls[i].BuildProfileTree(UniqueID, calcViewState); } } } internal object SaveControlStateInternal() { object controlState = SaveControlState(); object adapterControlState = null; if (_adapter != null) { adapterControlState = _adapter.SaveAdapterControlState(); } if (controlState != null || adapterControlState != null) { return new Pair(controlState, adapterControlState); } return null; } ///Gathers information about the control and delivers it to the ////// property to be displayed when tracing is enabled for the page. /// Save the control state, which is the essential state information needed even if view state is disabled. /// protected internal virtual object SaveControlState() { return null; } // Save modified state the control would like restored on the postback. // Return null if there is no state to save. ////// protected virtual object SaveViewState() { // Save values cached out of view state if (flags[visibleDirty]) { ViewState["Visible"] = !flags[invisible]; } if (_viewState != null) return _viewState.SaveViewState(); return null; } // Answer any state this control or its descendants want to save on freeze. // The format for saving is Triplet(myState, ArrayList childIDs, ArrayList childStates), // where myState or childStates and childIDs may be null. internal object SaveViewStateRecursive() { if (flags[disableViewState]) return null; object adapterState = null; if (_adapter != null) { adapterState = _adapter.SaveAdapterViewState(); } object controlSavedState = SaveViewState(); ArrayList childStates = null; if (HasControls()) { ControlCollection occasionalFieldControls = _occasionalFields.Controls; int occasionalFieldControlCount = occasionalFieldControls.Count; bool useId = LoadViewStateByID; for (int i = 0; i < occasionalFieldControlCount; i++) { Control child = occasionalFieldControls[i]; object childState = child.SaveViewStateRecursive(); if (childState != null) { if (childStates == null) { childStates = new ArrayList(occasionalFieldControlCount); } if (useId) { child.EnsureID(); childStates.Add(child.ID); } else { childStates.Add(i); } childStates.Add(childState); } } } if (_adapter != null) { if ((controlSavedState != null) || (adapterState != null) || (childStates != null)) { return new Triplet(controlSavedState, adapterState, childStates); } } else { if ((controlSavedState != null) || (childStates != null)) { return new Pair(controlSavedState, childStates); } } return null; } ////// Saves view state for use with a later ////// request. /// /// protected internal virtual void Render(HtmlTextWriter writer) { RenderChildren(writer); } internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children) { // If we have a delegate, use it for the rendering. // This happens when there is some ASP code. See also Whidbey 33012. if(RareFields != null && RareFields.RenderMethod != null ) { writer.BeginRender(); RareFields.RenderMethod(writer, this); writer.EndRender(); return; } if (children != null) { foreach (Control child in children) { child.RenderControl(writer); } } } protected internal virtual void RenderChildren(HtmlTextWriter writer) { ICollection children = (_occasionalFields == null) ? null : _occasionalFields.Controls; RenderChildrenInternal(writer, children); } ///Outputs control content to a provided HTMLTextWriter /// output stream. ////// public virtual void RenderControl(HtmlTextWriter writer) { //use the Adapter property to ensure it is resolved RenderControl(writer, Adapter); } ///[To be supplied.] ////// protected void RenderControl(HtmlTextWriter writer, ControlAdapter adapter) { if (!flags[invisible] && !flags[notVisibleOnPage]) { HttpContext context = (Page == null) ? null : Page._context; if (context != null && context.TraceIsEnabled) { int presize = context.Response.GetBufferedLength(); RenderControlInternal(writer, adapter); int postsize = context.Response.GetBufferedLength(); context.Trace.AddControlSize(UniqueID, postsize - presize); } else { RenderControlInternal(writer, adapter); } } } private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) { if (adapter != null) { // adapter.BeginRender(writer); adapter.Render(writer); adapter.EndRender(writer); } else { Render(writer); } } ///Used for MobilePage implementation. ////// protected internal virtual void OnUnload(EventArgs e) { if(HasEvents()) { EventHandler handler = _occasionalFields.Events[EventUnload] as EventHandler; if (handler != null) { handler(this, e); } } } ///[To be supplied.] ////// public virtual void Dispose() { IContainer container = null; if (Site != null) { container = (IContainer)Site.GetService(typeof(IContainer)); if (container != null) { container.Remove(this); EventHandler disp = Events[EventDisposed] as EventHandler; if (disp != null) disp(this, EventArgs.Empty); } } if (_occasionalFields != null) { _occasionalFields.Dispose(); //do not null out for backwards compat, VSWhidbey 475940 //_occasionalFields = null; } } internal virtual void UnloadRecursive(bool dispose) { Page page = Page; if (page != null && page.RequiresControlState(this)) { page.UnregisterRequiresControlState(this); RareFieldsEnsured.RequiredControlState = true; } // Remove the generated ID so it will be assigned a different ID next time. if (flags[useGeneratedID]) { _id = null; flags.Clear(useGeneratedID); } if (_occasionalFields != null && _occasionalFields.Controls != null) { string oldmsg = _occasionalFields.Controls.SetCollectionReadOnly(SR.Parent_collections_readonly); int controlCount = _occasionalFields.Controls.Count; for (int i = 0; i < controlCount; i++) _occasionalFields.Controls[i].UnloadRecursive(dispose); _occasionalFields.Controls.SetCollectionReadOnly(oldmsg); } if(_adapter != null) { _adapter.OnUnload(EventArgs.Empty); } else { OnUnload(EventArgs.Empty); } // if (dispose) Dispose(); // VSWhidbey 244999: Everett behavior doesn't reset the control state. // But for control which requires its OnInit method to be called again // to properly initialize when the control is removed and added back // to Page's control tree, the control can override IsReloadable // to true so the control state is reset. e.g. Validator, see bug if (IsReloadable) { _controlState = ControlState.Constructed; } } ///Enables a control to perform final cleanup. ////// protected void RaiseBubbleEvent(object source, EventArgs args) { Control currentTarget = Parent; while (currentTarget != null) { if (currentTarget.OnBubbleEvent(source, args)) { return; } currentTarget = currentTarget.Parent; } } ///Assigns an sources of the event and its information up the page control /// hierarchy until they reach the top of the control tree. ////// protected virtual bool OnBubbleEvent(object source, EventArgs args) { return false; } // Members related to being a container ///Determines whether the event for the control should be passed up the page's /// control hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_Controls) ] public virtual ControlCollection Controls { get { if (_occasionalFields == null || _occasionalFields.Controls == null) { EnsureOccasionalFields(); _occasionalFields.Controls = CreateControlCollection(); } return _occasionalFields.Controls; } } ///Gets a ControlCollection object that represents the child controls for a specified control in the /// UI hierarchy. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebSysDescription(SR.Control_State) ] protected virtual StateBag ViewState { get { if (_viewState != null) { // create a StateBag on demand; WebControl makes its case sensitive return _viewState; } _viewState = new StateBag(ViewStateIgnoresCase); if (IsTrackingViewState) _viewState.TrackViewState(); return _viewState; } } // fast enough that we cam always use it. ///Indicates a dictionary of state information that allows you to save and restore /// the state of a control across multiple requests for the same page. ////// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), ] protected virtual bool ViewStateIgnoresCase { get { return false; } } ///Indicates whether the ///object is case-insensitive. /// protected internal virtual void AddedControl(Control control, int index) { if (control.OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_NotAllowed)); } if (control._parent != null) { control._parent.Controls.Remove(control); } control._parent = this; control._page = Page; control.flags.Clear(designModeChecked); // We only add to naming container if it is available. Otherwise, it will be pushed through // during InitRecursive Control namingContainer = flags[isNamingContainer] ? this : _namingContainer; if (namingContainer != null) { control.UpdateNamingContainer(namingContainer); if (control._id == null && !control.flags[idNotRequired]) { // this will also dirty the name table in the naming container control.GenerateAutomaticID(); } else if (control._id != null || (control._occasionalFields != null && control._occasionalFields.Controls != null)) { // If the control has and ID, or has children (which *may* themselves // have ID's), we need to dirty the name table (ASURT 100557) namingContainer.DirtyNameTable(); } } /* * The following is for times when AddChild is called after CreateChildControls. This * allows users to add children at any time in the creation process without having * to understand the underlying machinery. * Note that if page is null, it means we haven't been attached to a container ourselves. * If this is true, when we are, our children will be recursively set up. */ if (_controlState >= ControlState.ChildrenInitialized) { Debug.Assert(namingContainer != null); control.InitRecursive(namingContainer); // VSWhidbey 396372: We need to reregister the control state if the control is reparented because the control // is unregistered during unload, but its already been inited once, so it will not get its Init called again // which is where most controls call RegisterRequiresControlState if (control._controlState >= ControlState.Initialized && control.RareFields != null && control.RareFields.RequiredControlState) { Page.RegisterRequiresControlState(control); } if (_controlState >= ControlState.ViewStateLoaded) { object viewState = null; if(_occasionalFields != null && _occasionalFields.ControlsViewState != null) { viewState = _occasionalFields.ControlsViewState[index]; // This solution takes the conservative approach that once viewstate has been // applied to a child control, it is thrown away. This eliminates inadvertently // setting viewstate on the wrong control, which can occur in scenarios where // the child control collection is being manipulated via code. Probably need // to provide a feature where programmer can control whether to reapply viewstate // or not. if (LoadViewStateByID) { control.EnsureID(); viewState = _occasionalFields.ControlsViewState[control.ID]; _occasionalFields.ControlsViewState.Remove(control.ID); } else { viewState = _occasionalFields.ControlsViewState[index]; _occasionalFields.ControlsViewState.Remove(index); } } control.LoadViewStateRecursive(viewState); if (_controlState >= ControlState.Loaded) { control.LoadRecursive(); if (_controlState >= ControlState.PreRendered) control.PreRenderRecursiveInternal(); } } } } ////// protected virtual ControlCollection CreateControlCollection() { return new ControlCollection(this); } ///[To be supplied.] ////// protected internal virtual void CreateChildControls() { } ////// Notifies any controls that use composition-based implementation to create any /// child controls they contain in preperation for postback or rendering. /// ////// protected bool ChildControlsCreated { get { return flags[controlsCreated]; } set { if (!value && flags[controlsCreated]) { Controls.Clear(); } if(value) { flags.Set(controlsCreated); } else { flags.Clear(controlsCreated); } } } ///Indicates whether the control's child controls have been created. ////// public string ResolveUrl(string relativeUrl) { if (relativeUrl == null) { throw new ArgumentNullException("relativeUrl"); } // check if its empty or already absolute if ((relativeUrl.Length == 0) || (UrlPath.IsRelativeUrl(relativeUrl) == false)) { return relativeUrl; } string baseUrl = AppRelativeTemplateSourceDirectory; if (String.IsNullOrEmpty(baseUrl)) { return relativeUrl; } // first make it absolute string url = UrlPath.Combine(baseUrl, relativeUrl); // include the session cookie if available (ASURT 47658) // As a side effect, this will change an app relative path (~/...) to app absolute return Context.Response.ApplyAppPathModifier(url); } ///Make a URL absolute using the AppRelativeTemplateSourceDirectory. The returned URL is for /// client use, and will contain the session cookie if appropriate. ////// public string ResolveClientUrl(string relativeUrl) { if (DesignMode && Page != null && Page.Site != null) { IUrlResolutionService resolutionService = (IUrlResolutionService)Page.Site.GetService(typeof(IUrlResolutionService)); if (resolutionService != null) { return resolutionService.ResolveClientUrl(relativeUrl); } } if (relativeUrl == null) { throw new ArgumentNullException("relativeUrl"); } // Get the app absolute TemplateSourceDirectory (not app relative) string tplSourceDir = VirtualPath.GetVirtualPathString(TemplateControlVirtualDirectory); if (String.IsNullOrEmpty(tplSourceDir)) return relativeUrl; string baseRequestDir = Context.Request.ClientBaseDir.VirtualPathString; // If the path is app relative (~/...), we cannot take shortcuts, since // the ~ is meaningless on the client, and must be resolved if (!UrlPath.IsAppRelativePath(relativeUrl)) { // If the template source directory is the same as the directory of the request, // we don't need to do any adjustments to the input path if (StringUtil.EqualsIgnoreCase(baseRequestDir, tplSourceDir)) return relativeUrl; // check if it's empty or absolute if ((relativeUrl.Length == 0) || (!UrlPath.IsRelativeUrl(relativeUrl))) { return relativeUrl; } } // first make it absolute string url = UrlPath.Combine(tplSourceDir, relativeUrl); // Make sure the path ends with a slash before calling MakeRelative baseRequestDir = UrlPath.AppendSlashToPathIfNeeded(baseRequestDir); // Now, make it relative to the current request, so that the client will // compute the correct path return HttpUtility.UrlPathEncode(UrlPath.MakeRelative(baseRequestDir, url)); } internal void DirtyNameTable() { Debug.Assert(this is INamingContainer); if(_occasionalFields != null) { _occasionalFields.NamedControls = null; } } private void EnsureNamedControlsTable() { Debug.Assert(this is INamingContainer); Debug.Assert(HasControls()); Debug.Assert(_occasionalFields != null); Debug.Assert(_occasionalFields.NamedControls == null); _occasionalFields.NamedControls = new HybridDictionary(/*initialSize*/ _occasionalFields.NamedControlsID, /*caseInsensitive*/ true); FillNamedControlsTable(this, _occasionalFields.Controls); } private void FillNamedControlsTable(Control namingContainer, ControlCollection controls) { Debug.Assert(namingContainer._occasionalFields != null); Debug.Assert(namingContainer._occasionalFields.NamedControls != null); Debug.Assert((controls != null) && (controls.Count != 0)); int controlCount = controls.Count; for (int i=0; i < controlCount; i++) { Control control = controls[i]; if (control._id != null) { #if DEBUG if (control._namingContainer != null) { Debug.Assert(control._namingContainer == namingContainer); } #endif // DEBUG try { namingContainer.EnsureOccasionalFields(); namingContainer._occasionalFields.NamedControls.Add(control._id, control); } catch { throw new HttpException(SR.GetString(SR.Duplicate_id_used, control._id, "FindControl")); } } if (control.HasControls() && (control.flags[isNamingContainer] == false)) { FillNamedControlsTable(namingContainer, control.Controls); } } } ///Return a URL that is suitable for use on the client. /// If the URL is absolute, return it unchanged. If it is relative, turn it into a /// relative URL that is correct from the point of view of the current request path /// (which is what the browser uses for resolution). ////// public virtual Control FindControl(String id) { return FindControl(id, 0); } ///Searches the current naming container for a control with /// the specified ///. /// /// protected virtual Control FindControl(String id, int pathOffset) { string childID; EnsureChildControls(); // If we're not the naming container, let it do the job if (!(flags[isNamingContainer])) { Control namingContainer = NamingContainer; if (namingContainer != null) { return namingContainer.FindControl(id, pathOffset); } return null; } // No registered control, demand create the named controls table //call HasControls ensuress _occasionalFields != null if(HasControls() && _occasionalFields.NamedControls == null) { EnsureNamedControlsTable(); } if (_occasionalFields == null || _occasionalFields.NamedControls == null) { return null; } // Need to support ':' for V1 backward compatibility. char[] findControlSeparators = { ID_SEPARATOR, LEGACY_ID_SEPARATOR }; // Is it a hierarchical name? int newPathOffset = id.IndexOfAny(findControlSeparators, pathOffset); // If not, handle it here if (newPathOffset == -1) { childID = id.Substring(pathOffset); return _occasionalFields.NamedControls[childID] as Control; } // Get the name of the child, and try to locate it childID = id.Substring(pathOffset, newPathOffset - pathOffset); Control child = _occasionalFields.NamedControls[childID] as Control; // Child doesn't exist: fail if (child == null) return null; return child.FindControl(id, newPathOffset + 1); } /* * Called when the controls of a naming container are cleared. */ internal void ClearNamingContainer() { Debug.Assert(this is INamingContainer); EnsureOccasionalFields(); _occasionalFields.NamedControlsID = 0; DirtyNameTable(); } ///Searches the current naming container for a control with the specified /// ///and an offset to aid in the /// search. /// /// [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] protected virtual IDictionary GetDesignModeState() { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.DesignModeState == null) { rareFields.DesignModeState = new HybridDictionary(); } return rareFields.DesignModeState; } ////// public virtual bool HasControls() { return _occasionalFields != null && _occasionalFields.Controls != null && _occasionalFields.Controls.Count > 0; } /* * Check if a Control either has children or has a compiled render method. * This is to address issues like ASURT 94127 */ internal bool HasRenderingData() { return HasControls() || HasRenderDelegate(); } /* * Check if a Control either has children or has a compiled render method. * This is to address issues like ASURT 94127 */ internal bool HasRenderDelegate() { if(RareFields != null) { return (RareFields.RenderMethod != null ); } return false; } /* * Returns true if the container contains just a static string, i.e., * when the Controls collection has a single LiteralControl. */ ///Determines if the current control contains any child /// controls. Since this method simply deteremines if any child controls exist at /// all, it can enhance performance by avoiding a call to the Count property, /// inherited from the ///class, on the /// property. /// protected bool IsLiteralContent() { return (_occasionalFields != null && _occasionalFields.Controls != null) && (_occasionalFields.Controls.Count == 1) && ((_occasionalFields.Controls[0] is LiteralControl)); } ///Determines if the container holds literal content only. /// When this method returns ////// , the container collection only holds a single literal control. The /// content is then passed to the requesting browser as HTML. /// protected bool IsTrackingViewState { get { return flags[marked]; } } ///Determines if view state changes to the /// ////// are being saved. /// protected virtual void TrackViewState() { if (_viewState != null) _viewState.TrackViewState(); flags.Set(marked); } ///Turns on tracking of view state changes to the control /// so that they can be stored in the ////// object. /// protected virtual void EnsureChildControls() { if (!ChildControlsCreated && !flags[creatingControls]) { flags.Set(creatingControls); try { ResolveAdapter(); if(_adapter != null) { _adapter.CreateChildControls(); } else { CreateChildControls(); } // Only set ChildControlsCreated = true if CreateChildControls() did not throw // an exception (VSWhidbey 465798). ChildControlsCreated = true; } finally { flags.Clear(creatingControls); } } } ///Checks that the control contains child controls; if it does not, it creates /// them. This includes any literal content being parsed as a ////// object. /// Used internally to store a ControlBuilder reference for the control. /// The builder will be used at design-time to help persist all the filtered properties /// of the control. /// internal void SetControlBuilder(ControlBuilder controlBuilder) { RareFieldsEnsured.ControlBuilder = controlBuilder; } ////// protected internal virtual void RemovedControl(Control control) { if (control.OwnerControl != null) { throw new InvalidOperationException(SR.GetString(SR.Substitution_NotAllowed)); } if ((_namingContainer != null) && (control._id != null)) { _namingContainer.DirtyNameTable(); } // Controls may need to do their own cleanup. control.UnloadRecursive(false); control._parent = null; control._page = null; control._namingContainer = null; // Don't reset _templateSourceVirtualDirectory on TemplateControl's, because // the path is their own, not their parent. i.e. it doesn't change no matter // where in the tree they end up. if (!(control is TemplateControl)) control._templateSourceVirtualDirectory = null; control._templateControl = null; control.flags.Clear(mustRenderID); control.ClearCachedUniqueIDRecursive(); } internal void SetDesignMode() { flags.Set(designMode); flags.Set(designModeChecked); } ////// /// protected virtual void SetDesignModeState(IDictionary data) { } // Set the delegate to the render method ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public void SetRenderMethodDelegate(RenderMethod renderMethod) { RareFieldsEnsured.RenderMethod = renderMethod; // Make the collection readonly if there are code blocks (ASURT 78810) Controls.SetCollectionReadOnly(SR.Collection_readonly_Codeblocks); } ///Assigns any event handler delegates for the control to match the parameters /// defined in the ///. /// /// bool IDataBindingsAccessor.HasDataBindings { get { return ((RareFields != null) && (RareFields.DataBindings != null) && (RareFields.DataBindings.Count != 0)); } } ///Returns whether the control contains any data binding logic. This method is /// only accessed by RAD designers. ////// /// DataBindingCollection IDataBindingsAccessor.DataBindings { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.DataBindings == null) { rareFields.DataBindings = new DataBindingCollection(); } return rareFields.DataBindings; } } // IParserAccessor interface // A sub-object tag was parsed by the parser; add it to this control. ///Indicates a collection of all data bindings on the control. This property is /// read-only. ////// /// void IParserAccessor.AddParsedSubObject(object obj) { AddParsedSubObject(obj); } internal string SpacerImageUrl { get { EnsureOccasionalFields(); if (_occasionalFields.SpacerImageUrl == null) { _occasionalFields.SpacerImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(WebControl), "Spacer.gif"); } return _occasionalFields.SpacerImageUrl; } } private Control OwnerControl { get { if (RareFields == null) { return null; } return RareFields.OwnerControl; } set { RareFieldsEnsured.OwnerControl = value; } } internal IPostBackDataHandler PostBackDataHandler { get { IPostBackDataHandler pbdh = _adapter as IPostBackDataHandler; if(pbdh != null) return pbdh; pbdh = this as IPostBackDataHandler; return pbdh; } } internal IPostBackEventHandler PostBackEventHandler { get { IPostBackEventHandler pbeh = _adapter as IPostBackEventHandler; if(pbeh != null) return pbeh; pbeh = this as IPostBackEventHandler; return pbeh; } } #if ORCAS internal bool NotVisibleOnPage { get { return flags[notVisibleOnPage]; } set { if(value) { flags.Set(notVisibleOnPage); } else { flags.Clear(notVisibleOnPage); } } } internal int VirtualStartPage { get { return RareFields != null ? RareFields.VirtualStartPage : -1; } set { RareFieldsEnsured.VirtualStartPage = value; } } internal int VirtualEndPage { get { return RareFields != null ? RareFields.VirtualEndPage : -1; } set { RareFieldsEnsured.VirtualEndPage = value; } } #endif #region IControlDesignerAccessor implementation ///Notifies the control that an element, XML or HTML, was parsed, and adds it to /// the control. ///IDictionary IControlDesignerAccessor.UserData { get { ControlRareFields rareFields = RareFieldsEnsured; if (rareFields.ControlDesignerAccessorUserData == null) { rareFields.ControlDesignerAccessorUserData = new HybridDictionary(); } return rareFields.ControlDesignerAccessorUserData; } } /// /// /// IDictionary IControlDesignerAccessor.GetDesignModeState() { return GetDesignModeState(); } ////// /// void IControlDesignerAccessor.SetDesignModeState(IDictionary data) { SetDesignModeState(data); } void IControlDesignerAccessor.SetOwnerControl(Control owner) { if (owner == this) { throw new ArgumentException(SR.GetString(SR.Control_CannotOwnSelf), "owner"); } OwnerControl = owner; _parent = owner.Parent; _page = owner.Page; } #endregion #region IControlBuilderAccessor implementation ////// /// A reference to the ControlBuilder that was used to construct this control (if there was one) /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] ControlBuilder IControlBuilderAccessor.ControlBuilder { get { return RareFields != null ? RareFields.ControlBuilder : null; } } #endregion IControlBuilderAccessor implementation #region IExpressionsAccessor ///bool IExpressionsAccessor.HasExpressions { get { if (RareFields == null) { return false; } ExpressionBindingCollection expressions = RareFields.ExpressionBindings; return ((expressions != null) && (expressions.Count > 0)); } } /// ExpressionBindingCollection IExpressionsAccessor.Expressions { get { ExpressionBindingCollection expressions = RareFieldsEnsured.ExpressionBindings; if (expressions == null) { expressions = new ExpressionBindingCollection(); RareFields.ExpressionBindings = expressions; } return expressions; } } #endregion private sealed class ControlRareFields : IDisposable { internal ControlRareFields() { } public ISite Site; public RenderMethod RenderMethod; // Reference to the templateControl that hosts this control. #if ORCAS public int VirtualStartPage = -1; public int VirtualEndPage = -1; public ContentPager ContentPager; #endif // Reference to the ControlBuilder used to build this control public ControlBuilder ControlBuilder; public DataBindingCollection DataBindings; public Control OwnerControl; public ExpressionBindingCollection ExpressionBindings; public bool RequiredControlState = false; // These fields are only used in the designer so we // keep them here to prevent memory bloat at runtime public IDictionary ControlDesignerAccessorUserData; public IDictionary DesignModeState; public void Dispose() { //do not null out for backwards compat, VSWhidbey 475940 //Site = null; //RenderMethod = null; //DataBindings = null; //OwnerControl = null; //ExpressionBindings = null; ControlBuilder = null; if (OwnerControl != null) { OwnerControl.Dispose(); } ControlDesignerAccessorUserData = null; DesignModeState = null; #if ORCAS ContentPager = null; #endif } } private sealed class OccasionalFields : IDisposable { internal OccasionalFields() { } public string SkinId; // Events public EventHandlerList Events; public IDictionary ControlsViewState; public ControlCollection Controls; public int NamedControlsID; // Only used if we are a naming container. It contains all the controls // in the namespace. public IDictionary NamedControls; public ControlRareFields RareFields; public String UniqueIDPrefix; public string SpacerImageUrl; public void Dispose() { if (Events != null) { Events.Dispose(); Events = null; } if (RareFields != null) { RareFields.Dispose(); } ControlsViewState = null; //do not null out for backwards compat, VSWhidbey 475940 //Controls = null; //NamedControls = null; //UniqueIDPrefix = null; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SerializationAttributes.cs
- PointAnimationUsingKeyFrames.cs
- BaseProcessor.cs
- SymmetricKey.cs
- WrapperSecurityCommunicationObject.cs
- KnownIds.cs
- GroupQuery.cs
- PeerCollaborationPermission.cs
- FixUp.cs
- SqlUtil.cs
- MimePart.cs
- SimpleHandlerBuildProvider.cs
- DocumentOrderQuery.cs
- PeerNameRegistration.cs
- SqlDataSourceCommandEventArgs.cs
- Style.cs
- StateItem.cs
- DataColumn.cs
- SafeHandles.cs
- DispatcherTimer.cs
- GlobalizationSection.cs
- _SecureChannel.cs
- HwndSource.cs
- ValidationHelper.cs
- TrackingProfileManager.cs
- SqlNodeAnnotations.cs
- MDIWindowDialog.cs
- AutomationPropertyInfo.cs
- SaveFileDialog.cs
- basevalidator.cs
- RawStylusSystemGestureInputReport.cs
- TemplateControlCodeDomTreeGenerator.cs
- ReaderWriterLock.cs
- ConnectionStringsExpressionBuilder.cs
- FactoryMaker.cs
- StateRuntime.cs
- SevenBitStream.cs
- ReadOnlyPropertyMetadata.cs
- TemplateBindingExpressionConverter.cs
- WindowVisualStateTracker.cs
- WebControlAdapter.cs
- AssemblyName.cs
- BufferedStream.cs
- Module.cs
- StrongNameMembershipCondition.cs
- ObjectNavigationPropertyMapping.cs
- ReadWriteSpinLock.cs
- BCLDebug.cs
- ComplusTypeValidator.cs
- SchemaLookupTable.cs
- TextParaLineResult.cs
- ControlCachePolicy.cs
- PropertyKey.cs
- AssemblySettingAttributes.cs
- AuthenticationSchemesHelper.cs
- SendingRequestEventArgs.cs
- BinaryMethodMessage.cs
- CrossContextChannel.cs
- SmtpNegotiateAuthenticationModule.cs
- EmptyStringExpandableObjectConverter.cs
- OdbcPermission.cs
- ExtenderControl.cs
- XmlSchemaInferenceException.cs
- HttpRawResponse.cs
- DataGridItemAutomationPeer.cs
- ConfigXmlSignificantWhitespace.cs
- BamlTreeMap.cs
- WebPartDescription.cs
- VersionedStreamOwner.cs
- LinkArea.cs
- RtfNavigator.cs
- WindowsFormsHelpers.cs
- DBCSCodePageEncoding.cs
- DataControlFieldHeaderCell.cs
- CallbackValidator.cs
- WindowManager.cs
- LinearKeyFrames.cs
- DragSelectionMessageFilter.cs
- CachedPathData.cs
- UserThread.cs
- MsmqInputChannelListener.cs
- SqlError.cs
- ObjectDisposedException.cs
- SegmentInfo.cs
- login.cs
- IconConverter.cs
- TheQuery.cs
- Label.cs
- PropertyGridCommands.cs
- WindowsButton.cs
- recordstatescratchpad.cs
- NamespaceCollection.cs
- HostExecutionContextManager.cs
- QueryGenerator.cs
- CategoryGridEntry.cs
- ExitEventArgs.cs
- DataSourceSelectArguments.cs
- XmlDownloadManager.cs
- Activator.cs
- DataServiceRequest.cs