File: UI\Control.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="Control.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.UI {
    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.Caching;
    using System.Web.Configuration;
    using System.Web.Hosting;
    using System.Web.Routing;
    using System.Web.UI.Adapters;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.Util;
    using HttpException = System.Web.HttpException;
 
    // 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.</para>
    [
    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)
    ]
    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 string _cachedPredictableID;
        private Control _parent;
 
        // fields related to being a container
        private ControlState _controlState;
        private StateBag _viewState;
 
        private EventHandlerList _events;
        private ControlCollection _controls;
 
        // 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;
        // The virtual directory of the Page or UserControl that hosts this control.
 
        // 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;
        private const int validateRequestModeDirty  = 0x00400000;
        private const int viewStateNotInherited     = 0x00800000;
        private const int viewStateMode             = 0x01000000;
        private const int clientIDMode              = 0x06000000;
        private const int clientIDModeOffset        = 25;
        private const int effectiveClientIDMode     = 0x18000000;
        private const int effectiveClientIDModeOffset = 27;
        private const int validateRequestMode       = 0x60000000;
        private const int validateRequestModeOffset = 29;
        #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"
 
        };
 
        /// <devdoc>
        /// <para>Initializes a new instance of the <see cref='System.Web.UI.Control'/> class.</para>
        /// </devdoc>
        public Control() {
            if (this is INamingContainer)
                flags.Set(isNamingContainer);
        }
 
        private ClientIDMode ClientIDModeValue {
            get {
                return (ClientIDMode)flags[clientIDMode, clientIDModeOffset];
            }
            set {
                flags[clientIDMode, clientIDModeOffset] = (int)value;
            }
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1706:ShortAcronymsShouldBeUppercase", MessageId="Member")]
        [
        DefaultValue(ClientIDMode.Inherit),
        Themeable(false),
        WebCategory("Behavior"),
        WebSysDescription(SR.Control_ClientIDMode)
        ]
        public virtual ClientIDMode ClientIDMode {
            get {
                return ClientIDModeValue;
            }
            set {
                if (ClientIDModeValue != value) {
                    if (value != EffectiveClientIDModeValue) {
                        ClearEffectiveClientIDMode();
                        ClearCachedClientID();
                    }
                    ClientIDModeValue = value;
                }
            }
        }
 
        private ClientIDMode EffectiveClientIDModeValue {
            get {
                return (ClientIDMode)flags[effectiveClientIDMode, effectiveClientIDModeOffset];
            }
            set {
                flags[effectiveClientIDMode, effectiveClientIDModeOffset] = (int)value;
            }
        }
 
        internal virtual ClientIDMode EffectiveClientIDMode {
            get {
                if (EffectiveClientIDModeValue == ClientIDMode.Inherit) {
                    EffectiveClientIDModeValue = ClientIDMode;
                    if (EffectiveClientIDModeValue == ClientIDMode.Inherit) {
                        if (NamingContainer != null) {
                            EffectiveClientIDModeValue = NamingContainer.EffectiveClientIDMode;
                        }
                        else {
                            HttpContext context = Context;
                            if (context != null) {
                                EffectiveClientIDModeValue = RuntimeConfig.GetConfig(context).Pages.ClientIDMode;
                            }
                            else {
                                EffectiveClientIDModeValue = RuntimeConfig.GetConfig().Pages.ClientIDMode;
                            }
                        }
                    }
                }
                return EffectiveClientIDModeValue;
            }
        }
 
        internal string UniqueClientID {
            get {
                string uniqueID = UniqueID;
                if(uniqueID != null && uniqueID.IndexOf(IdSeparator) >= 0) {
                    return uniqueID.Replace(IdSeparator, ID_RENDER_SEPARATOR);
                }
                return uniqueID;
            }
        }
 
        internal string StaticClientID {
            get {
                return flags[useGeneratedID] ? String.Empty : ID ?? String.Empty;
            }
        }
 
        internal ControlAdapter AdapterInternal {
            get {
                if (_occasionalFields == null ||
                    _occasionalFields.RareFields == null ||
                    _occasionalFields.RareFields.Adapter == null) {
                        return null;
                }
                return _occasionalFields.RareFields.Adapter;
            }
            set {
                if (value != null) {
                    RareFieldsEnsured.Adapter = value;
                }
                else {
                    if (_occasionalFields != null &&
                        _occasionalFields.RareFields != null &&
                        _occasionalFields.RareFields.Adapter != null) {
                            _occasionalFields.RareFields.Adapter = null;
                    }
                }
            }
        }
        
        private string GetClientID() {
            switch (EffectiveClientIDMode) {
                case ClientIDMode.Predictable:
                    return PredictableClientID;
                case ClientIDMode.Static:
                    return StaticClientID;
                default:
                    return UniqueClientID;
            }
        }
 
        private string GetPredictableClientIDPrefix() {
            string predictableIDPrefix;
 
            Control namingContainer = NamingContainer;
            if (namingContainer != null) {
                if (_id == null) {
                    GenerateAutomaticID();
                }
                if (namingContainer is Page || namingContainer is MasterPage) {
                    predictableIDPrefix = _id;
                }
                else {
                    predictableIDPrefix = namingContainer.GetClientID();
                    if (String.IsNullOrEmpty(predictableIDPrefix)) {
                        predictableIDPrefix = _id;
                    }
                    else {
                        if (!String.IsNullOrEmpty(_id) && (!(this is IDataItemContainer) || (this is IDataBoundItemControl))) {
                            predictableIDPrefix = predictableIDPrefix + ID_RENDER_SEPARATOR + _id;
                        }
                    }
                }
            }
            else {
                predictableIDPrefix = _id;
            }
            return predictableIDPrefix;
        }
 
        private string GetPredictableClientIDSuffix() {
            string predictableIDSuffix = null;
 
            Control dataItemContainer = DataItemContainer;
            if (dataItemContainer != null && 
                !(dataItemContainer is IDataBoundItemControl) &&
                (!(this is IDataItemContainer) || (this is IDataBoundItemControl))) {
                Control dataKeysContainer = dataItemContainer.DataKeysContainer;
                if (dataKeysContainer != null && (((IDataKeysControl)dataKeysContainer).ClientIDRowSuffix != null) && (((IDataKeysControl)dataKeysContainer).ClientIDRowSuffix.Length > 0)) {
                    predictableIDSuffix = String.Empty;
                    IOrderedDictionary dataKey = ((IDataKeysControl)dataKeysContainer).ClientIDRowSuffixDataKeys[((IDataItemContainer)dataItemContainer).DisplayIndex].Values;
                    foreach (string suffixName in ((IDataKeysControl)dataKeysContainer).ClientIDRowSuffix) {
                        predictableIDSuffix = predictableIDSuffix + ID_RENDER_SEPARATOR + dataKey[suffixName].ToString();
                    }
                }
                else {
                    int index = ((IDataItemContainer)dataItemContainer).DisplayIndex;
                    if (index >= 0) {
                        predictableIDSuffix = ID_RENDER_SEPARATOR + index.ToString(CultureInfo.InvariantCulture);
                    }
                }
            }
            return predictableIDSuffix;
        }
 
        internal string PredictableClientID {
            get {
                if (_cachedPredictableID != null) {
                    return _cachedPredictableID;
                }
 
                _cachedPredictableID = GetPredictableClientIDPrefix();
                string suffixID = GetPredictableClientIDSuffix();
 
                // Concatenates Predictable clientID and ClientIDRowSuffix if available
                if (!String.IsNullOrEmpty(suffixID)) {
                    if (!String.IsNullOrEmpty(_cachedPredictableID)) {
                        _cachedPredictableID = _cachedPredictableID + suffixID;
                    }
                    else {
                        _cachedPredictableID = suffixID.Substring(1);
                    }
                }
                return String.IsNullOrEmpty(_cachedPredictableID) ? String.Empty : _cachedPredictableID;
            }
        }
 
        /// <devdoc>
        ///    <para>Indicates the control identifier generated by the ASP.NET framework. </para>
        /// </devdoc>
        [
        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 {
                if (EffectiveClientIDMode != ClientIDMode.Static) {
                    // 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();
                }
                return GetClientID();
            }
        }
 
        protected char ClientIDSeparator {
            get {
                return ID_RENDER_SEPARATOR;
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        WebSysDescription(SR.Control_OnDisposed)
        ]
        public event EventHandler Disposed {
            add {
                Events.AddHandler(EventDisposed, value);
            }
            remove {
                Events.RemoveHandler(EventDisposed, value);
            }
        }
 
        /// <devdoc>
        /// <para>Gets the <see langword='HttpContext'/> object of the current Web request. If
        ///    the control's context is <see langword='null'/>, this will be the context of the
        ///    control's parent, unless the parent control's context is <see langword='null'/>.
        ///    If this is the case, this will be equal to the HttpContext property.</para>
        /// </devdoc>
        [
        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 AdapterInternal;
            }
            if (DesignMode) {
                flags.Set(controlAdapterResolved);
                return null;
            }
 
            HttpContext context = Context;
            if (context != null && context.Request.Browser != null) {
                AdapterInternal = context.Request.Browser.GetAdapter(this);
            }
            flags.Set(controlAdapterResolved);
            return AdapterInternal;
        }
 
        /// <devdoc>
        ///    <para>Indicates the list of event handler delegates for the control. This property
        ///       is read-only.</para>
        /// </devdoc>
        protected ControlAdapter Adapter {
            get {
                if(flags[controlAdapterResolved]) {
                    return AdapterInternal;
                }
                AdapterInternal = ResolveAdapter();
                flags.Set(controlAdapterResolved);
                return AdapterInternal;
            }
        }
 
        /// <devdoc>
        /// Indicates whether a control is being used in the context of a design surface.
        /// </devdoc>
        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());
            }
        }
 
        /// <devdoc>
        ///    <para>Indicates the list of event handler delegates for the control. This property
        ///       is read-only.</para>
        /// </devdoc>
        protected EventHandlerList Events {
            get {
                if (_events == null) {
                    _events = new EventHandlerList();
                }
                return _events;
            }
        }
 
        protected bool HasEvents() {
            return (_events != null);
        }
 
        /// <devdoc>
        ///    <para> 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.</para>
        /// </devdoc>
        [
        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();
                }
 
                if (oldID != null && oldID != _id) {
                    ClearCachedClientID();
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para>Gets and sets a value indicating whether theme is enabled.</para>
        /// </devdoc>
        [
        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];
            }
        }
 
 
        /// <devdoc>
        ///    <para>Gets and sets the skinID of the control.</para>
        /// </devdoc>
        [
        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();
            }
        }
 
 
        /// <devdoc>
        ///    <para>
        ///       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.
        ///    </para>
        /// </devdoc>
        [
        DefaultValue(EnableViewStateDefault),
        Themeable(false),
        WebCategory("Behavior"),
        WebSysDescription(SR.Control_MaintainState)
        ]
        public virtual bool EnableViewState {
            get {
                return !flags[disableViewState];
            }
            set {
                SetEnableViewStateInternal(value);
            }
        }
 
        [
        DefaultValue(ViewStateMode.Inherit),
        Themeable(false),
        WebCategory("Behavior"),
        WebSysDescription(SR.Control_ViewStateMode)
        ]
        public virtual ViewStateMode ViewStateMode {
            get {
                return flags[viewStateNotInherited] ?
                    (flags[viewStateMode] ? ViewStateMode.Enabled : ViewStateMode.Disabled) :
                    ViewStateMode.Inherit;
            }
            set {
                if ((value < ViewStateMode.Inherit) || (value > ViewStateMode.Disabled)) {
                    throw new ArgumentOutOfRangeException("value");
                }
                if (value == ViewStateMode.Inherit) {
                    flags.Clear(viewStateNotInherited);
                }
                else {
                    flags.Set(viewStateNotInherited);
                    if (value == ViewStateMode.Enabled) { 
                        flags.Set(viewStateMode);
                    }
                    else {
                        flags.Clear(viewStateMode);
                    }
                }
            }
        }
 
 
        internal void SetEnableViewStateInternal(bool value) {
            if (!value)
                flags.Set(disableViewState);
            else
                flags.Clear(disableViewState);
        }
 
 
        /// <devdoc>
        /// 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.
        /// </devdoc>
        protected internal bool IsViewStateEnabled {
            get {
                Control current = this;
                while (current != null) {
                    if (current.EnableViewState == false) {
                        return false;
                    }
                    ViewStateMode mode = current.ViewStateMode;
                    if (mode != ViewStateMode.Inherit) {
                        return (mode == ViewStateMode.Enabled);
                    }
                    current = current.Parent;
                }
                return true;
            }
        }
 
 
        /// <devdoc>
        ///    <para>Gets the reference to the current control's naming container.</para>
        /// </devdoc>
        [
        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;
            }
        }
 
        /// <internalonly/>
        /// <devdoc>
        ///    <para>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)</para>
        ///     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.
        /// </devdoc>
        [
        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;
            }
        }
 
        [
        Bindable(false),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public Control DataItemContainer {
            get {
                Control dataItemContainer = NamingContainer;
                while (dataItemContainer != null && !(dataItemContainer is IDataItemContainer)) {
                    dataItemContainer = dataItemContainer.DataItemContainer;
                }
 
                return dataItemContainer;
            }
        }
 
        [
        Bindable(false),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public Control DataKeysContainer {
            get {
                Control dataKeysContainer = NamingContainer;
                while (dataKeysContainer != null && !(dataKeysContainer is IDataKeysControl)) {
                    dataKeysContainer = dataKeysContainer.DataKeysContainer;
                }
 
                return dataKeysContainer;
            }
        }
 
 
 
        /// <internalonly/>
        /// <devdoc>
        /// VSWhidbey 80467: Need to adapt id separator.
        /// </devdoc>
        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());
            }
        }
 
        /// <devdoc>
        /// <para> Gets the <see cref='System.Web.UI.Page'/> object that contains the
        ///    current control.</para>
        /// </devdoc>
        [
        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;
            }
        }
 
        internal RouteCollection RouteCollection {
            get {
                if (_occasionalFields == null ||
                    _occasionalFields.RareFields == null ||
                    _occasionalFields.RareFields.RouteCollection == null) {
                        return RouteTable.Routes;
                }
                return _occasionalFields.RareFields.RouteCollection;
            }
            set {
                if (value != null) {
                    RareFieldsEnsured.RouteCollection = value;
                }
                else {
                    if (_occasionalFields != null &&
                        _occasionalFields.RareFields != null &&
                        _occasionalFields.RareFields.RouteCollection != null) {
                            _occasionalFields.RareFields.RouteCollection = null;
                    }
                }
            }
        }
 
        // 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;
        }
 
        [
        Bindable(false),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ]
        public virtual Version RenderingCompatibility {
            get {
                if (_occasionalFields == null ||
                    _occasionalFields.RareFields == null ||
                    _occasionalFields.RareFields.RenderingCompatibility == null) {
                        return RuntimeConfig.Pages.ControlRenderingCompatibilityVersion;
                }
                return _occasionalFields.RareFields.RenderingCompatibility;
            }
            set {
                if (value != null) {
                    RareFieldsEnsured.RenderingCompatibility = value;
                }
                else {
                    if (_occasionalFields != null &&
                        _occasionalFields.RareFields != null &&
                        _occasionalFields.RareFields.RenderingCompatibility != null) {
                            _occasionalFields.RareFields.RenderingCompatibility = null;
                    }
                }
            }
        }
 
        private RuntimeConfig RuntimeConfig {
            get {
                HttpContext context = Context;
                if (context != null) {
                    // if context is available, use the most efficient way to get the config
                    return RuntimeConfig.GetConfig(context);
                } else {
                    return RuntimeConfig.GetConfig();
                }
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "Consistent with other URL properties in ASP.NET.")]
        public string GetRouteUrl(object routeParameters) {
            return GetRouteUrl(new RouteValueDictionary(routeParameters));
        }
 
        [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "Consistent with other URL properties in ASP.NET.")]
        public string GetRouteUrl(string routeName, object routeParameters) {
            return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters));
        }
 
        [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "Consistent with other URL properties in ASP.NET.")]
        public string GetRouteUrl(RouteValueDictionary routeParameters) {
            return GetRouteUrl(null, routeParameters);
        }
 
        [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "Consistent with other URL properties in ASP.NET.")]
        public string GetRouteUrl(string routeName, RouteValueDictionary routeParameters) {
            VirtualPathData data = RouteCollection.GetVirtualPath(Context.Request.RequestContext, routeName, routeParameters);
            if (data != null) {
                return data.VirtualPath;
            }
            return null;
        }
 
        /// <devdoc>
        ///    <para>Gets the reference to the <see cref='System.Web.UI.TemplateControl'/>
        ///    that hosts the control.</para>
        /// </devdoc>
        internal virtual TemplateControl GetTemplateControl() {
            if (_occasionalFields == null || _occasionalFields.TemplateControl == null) {
                if (Parent != null) {
                    TemplateControl templateControl = Parent.GetTemplateControl();
                    if (templateControl != null) {
                        EnsureOccasionalFields();
                        _occasionalFields.TemplateControl = templateControl;
                    }
                }
            }
            return (_occasionalFields != null) ? _occasionalFields.TemplateControl : null;
        }
 
 
        /// <devdoc>
        ///    <para>Gets the reference to the <see cref='System.Web.UI.TemplateControl'/>
        ///    that hosts the control.</para>
        /// </devdoc>
        [
        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.
                if (value != null) {
                    EnsureOccasionalFields();
                    _occasionalFields.TemplateControl = value;
                }
                else {
                    if (_occasionalFields != null &&
                        _occasionalFields.TemplateControl != null) {
                            _occasionalFields.TemplateControl = null;
                    }
                }
            }
        }
 
        /*
         * 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);
        }
 
 
        /// <devdoc>
        ///    <para> Gets the current control's parent control in the UI hierarchy.</para>
        /// </devdoc>
        [
        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;
            }
        }
 
        /// <devdoc>
        ///    <para> Gets the virtual directory of the Page or UserControl that contains this control.</para>
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebSysDescription(SR.Control_TemplateSourceDirectory)
        ]
        public virtual string TemplateSourceDirectory {
            get {
                if (TemplateControlVirtualDirectory == null)
                    return String.Empty;
 
                return TemplateControlVirtualDirectory.VirtualPathStringNoTrailingSlash;
            }
        }
 
 
        /// <devdoc>
        ///    <para> Gets the virtual directory of the Page or UserControl that contains this control.
        ///         Unlike TemplateSourceDirectory, this returns an app relative path (e.g. "~/sub")</para>
        /// </devdoc>
        [
        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 (_occasionalFields != null && _occasionalFields.TemplateSourceVirtualDirectory != null)
                    return _occasionalFields.TemplateSourceVirtualDirectory;
 
                TemplateControl control = TemplateControl;
                if (control == null) {
                    HttpContext context = Context;
                    if (context != null) {
                        VirtualPath templateSourceVirtualDirectory = context.Request.CurrentExecutionFilePathObject.Parent;
                        if (templateSourceVirtualDirectory != null) {
                            EnsureOccasionalFields();
                            _occasionalFields.TemplateSourceVirtualDirectory = templateSourceVirtualDirectory;
                        }
                    }
                    return (_occasionalFields != null) ? _occasionalFields.TemplateSourceVirtualDirectory : null;
                }
                // Prevent recursion if this is the TemplateControl
                if (control != this) {
                    VirtualPath templateSourceVirtualDirectory = control.TemplateControlVirtualDirectory;
                    if (templateSourceVirtualDirectory != null) {
                        EnsureOccasionalFields();
                        _occasionalFields.TemplateSourceVirtualDirectory = templateSourceVirtualDirectory;
                    }
                }
                return (_occasionalFields != null) ? _occasionalFields.TemplateSourceVirtualDirectory : null;
            }
 
            set {
                // This setter is necessary so that skins are based on hosting skin file.
                if (value != null) {
                    EnsureOccasionalFields();
                    _occasionalFields.TemplateSourceVirtualDirectory = value;
                }
                else {
                    if (_occasionalFields != null &&
                        _occasionalFields.TemplateSourceVirtualDirectory != null) {
                            _occasionalFields.TemplateSourceVirtualDirectory = null;
                    }
                }
            }
        }
 
        internal ControlState ControlState {
            get { return _controlState; }
            set { _controlState = value; }
        }
 
 
        /// <devdoc>
        ///    <para>Indicates the site information for the control.</para>
        /// </devdoc>
        [
        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);
            }
        }
 
 
        /// <devdoc>
        ///    <para>
        ///       Gets or sets a value that indicates whether a control should be rendered on
        ///       the page.
        ///    </para>
        /// </devdoc>
        [
        Bindable(true),
        DefaultValue(true),
        WebCategory("Behavior"),
        WebSysDescription(SR.Control_Visible)
        ]
        public virtual bool Visible {
            get {
                if (flags[invisible])
                    return false;
                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);
                }
            }
        }
 
 
        /// <devdoc>
        /// 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.
        /// </devdoc>
        private void ResetVisible() {
            Visible = true;
        }
 
 
        /// <devdoc>
        /// 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.
        /// </devdoc>
        private bool ShouldSerializeVisible() {
            return flags[invisible];
        }
 
 
        /// <devdoc>
        ///    <para> 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.</para>
        /// </devdoc>
        [
        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;
                }
            }
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID", Justification="This is consistent with UniqueID")]
        [SuppressMessage("Microsoft.Naming", "CA1706:ShortAcronymsShouldBeUppercase", MessageId = "Member", Justification="This is consistent with UniqueID")]
        public string GetUniqueIDRelativeTo(Control control) {
            if (control == null) {
                throw new ArgumentNullException("control");
            }
 
            if (!IsDescendentOf(control.NamingContainer)) {
                throw new InvalidOperationException(SR.GetString(SR.Control_NotADescendentOfNamingContainer, control.ID));
            }
 
            if (control.NamingContainer == Page) {
                return UniqueID;
            } else {
                return UniqueID.Substring(control.NamingContainer.UniqueID.Length + 1); // add 1 for the ID seperator (which is a char)
            }
        }
 
        /// <devdoc>
        ///    <para>Occurs when the control binds to a data source. Notifies the control to perform any data binding during this event.</para>
        /// </devdoc>
        [
        WebCategory("Data"),
        WebSysDescription(SR.Control_OnDataBind)
        ]
        public event EventHandler DataBinding {
            add {
                Events.AddHandler(EventDataBinding, value);
            }
            remove {
                Events.RemoveHandler(EventDataBinding, value);
            }
        }
 
 
        /// <devdoc>
        ///    <para>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.</para>
        /// </devdoc>
        [
        WebSysDescription(SR.Control_OnInit)
        ]
        public event EventHandler Init {
            add {
                Events.AddHandler(EventInit, value);
            }
            remove {
                Events.RemoveHandler(EventInit, value);
            }
        }
 
 
        /// <devdoc>
        /// <para>Occurs when the control is loaded to the <see cref='System.Web.UI.Page'/> object. Notifies the control to perform any steps that
        ///    need to occur on each page request.</para>
        /// </devdoc>
        [
        WebSysDescription(SR.Control_OnLoad)
        ]
        public event EventHandler Load {
            add {
                Events.AddHandler(EventLoad, value);
            }
            remove {
                Events.RemoveHandler(EventLoad, value);
            }
        }
 
 
        /// <devdoc>
        ///    <para>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 <see cref='System.Web.UI.Page'/> object.</para>
        /// </devdoc>
        [
        WebSysDescription(SR.Control_OnPreRender)
        ]
        public event EventHandler PreRender {
            add {
                Events.AddHandler(EventPreRender, value);
            }
            remove {
                Events.RemoveHandler(EventPreRender, value);
            }
        }
 
 
        /// <devdoc>
        ///    <para>Occurs when the control is unloaded from memory. Controls should perform any
        ///       final cleanup before this instance of it is </para>
        /// </devdoc>
        [
        WebSysDescription(SR.Control_OnUnload)
        ]
        public event EventHandler Unload {
            add {
                Events.AddHandler(EventUnload, value);
            }
            remove {
                Events.RemoveHandler(EventUnload, value);
            }
        }
 
        /// <devdoc>
        /// <para>Apply stylesheet skin on the control.</para>
        /// </devdoc>
        [
        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);
            }
        }
 
        /// <devdoc>
        /// <para>Apply theme on the control.</para>
        /// </devdoc>
        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);
            }
        }
 
 
        /// <devdoc>
        /// <para>Raises the <see langword='DataBinding'/> event. This
        ///    notifies a control to perform any data binding logic that is associated with it.</para>
        /// </devdoc>
        protected virtual void OnDataBinding(EventArgs e) {
            if(HasEvents()) {
                EventHandler handler = _events[EventDataBinding] as EventHandler;
                if(handler != null) {
                    handler(this, e);
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para> Causes data binding to occur on the invoked control and all of its child
        ///       controls.</para>
        /// </devdoc>
        public virtual void DataBind() {
            DataBind(true);
        }
 
        /// <devdoc>
        ///    <para> 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.</para>
        /// </devdoc>
        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();
                }
            }
        }
 
 
        /// <devdoc>
        /// <para> Causes data binding to occur on all of the child controls.</para>
        /// </devdoc>
        protected virtual void DataBindChildren() {
            if (HasControls()) {
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                try {
                    try {
                        int controlCount = _controls.Count;
                        for (int i=0; i < controlCount; i++)
                            _controls[i].DataBind();
                    }
                    finally {
                        _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);
            }
        }
 
 
        /// <devdoc>
        ///    <para>Notifies the control that an element, XML or HTML, was parsed, and adds it to
        ///       the control.</para>
        /// </devdoc>
        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 != null && _namingContainer != namingContainer)) {
                ClearCachedUniqueIDRecursive();
            }
 
            // No need to clear the cache if never been initialized
            if (EffectiveClientIDModeValue != ClientIDMode.Inherit) {
                ClearCachedClientID();
                ClearEffectiveClientIDMode();
            }
 
            _namingContainer = namingContainer;
        }
 
        private void ClearCachedUniqueIDRecursive() {
            _cachedUniqueID = null;
 
            if (_occasionalFields != null) {
                _occasionalFields.UniqueIDPrefix = null;
            }
 
            if (_controls != null) {
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    _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;
        }
 
        /// <devdoc>
        /// <para>Raises the <see langword='Init'/> event. This notifies the control to perform
        ///    any steps necessary for its creation on a page request.</para>
        /// </devdoc>
        protected internal virtual void OnInit(EventArgs e) {
            if(HasEvents()) {
                EventHandler handler = _events[EventInit] as EventHandler;
                if(handler != null) {
                    handler(this, e);
                }
            }
        }
 
        // !! IMPORTANT !!
        // If you make changes to this method, also change InitRecursiveAsync.
        internal virtual void InitRecursive(Control namingContainer) {
            ResolveAdapter();
            if (_controls != null) {
                if (flags[isNamingContainer]) {
                    namingContainer = this;
                }
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    Control control = _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);
                }
                _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 (AdapterInternal != null) {
                    AdapterInternal.OnInit(EventArgs.Empty);
                }
                else {
                    OnInit(EventArgs.Empty);
                }
 
                _controlState = ControlState.Initialized;
            }
 
            // track all subsequent state changes
            TrackViewState();
 
#if DEBUG
            ControlInvariant();
#endif
        }
 
        // TAP version of InitRecursive
        // !! IMPORTANT !!
        // If you make changes to this method, also change InitRecursive.
        internal async Task InitRecursiveAsync(Control namingContainer, Page page) {
            ResolveAdapter();
            if (_controls != null) {
                if (flags[isNamingContainer]) {
                    namingContainer = this;
                }
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    Control control = _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);
                }
                _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);
                    }
                }
 
                using (page.Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
                    if (AdapterInternal != null) {
                        AdapterInternal.OnInit(EventArgs.Empty);
                    }
                    else {
                        OnInit(EventArgs.Empty);
                    }
                    await page.GetWaitForPreviousStepCompletionAwaitable();
                }
 
                _controlState = ControlState.Initialized;
            }
 
            // track all subsequent state changes
            TrackViewState();
 
#if DEBUG
            ControlInvariant();
#endif
        }
 
#if DEBUG

        /// <devdoc>
        ///    <para>This should be used to assert internal state about the control</para>
        /// </devdoc>
        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 (_controls == null)
                    return;
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    Control control = _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);
            }
        }
 
 
        /// <devdoc>
        ///    <para>Deletes the view state information for all of the current control's child
        ///       controls.</para>
        /// </devdoc>
        protected void ClearChildViewState() {
            if(_occasionalFields != null) {
                _occasionalFields.ControlsViewState = null;
            }
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1706:ShortAcronymsShouldBeUppercase", MessageId="Member")]
        protected void ClearEffectiveClientIDMode() {
            EffectiveClientIDModeValue = ClientIDMode.Inherit;
            if (HasControls()) {
                foreach (Control control in Controls) {
                    control.ClearEffectiveClientIDMode();
                }
            }
        }
 
        [SuppressMessage("Microsoft.Naming", "CA1706:ShortAcronymsShouldBeUppercase", MessageId="Member")]
        protected void ClearCachedClientID() {
            _cachedPredictableID = null;
            if (HasControls()) {
                foreach (Control control in Controls) {
                    control.ClearCachedClientID();
                }
            }
        }
 
        /// <devdoc>
        ///    <para>Indicates whether the current control's children have any saved view state
        ///       information. This property is read-only.</para>
        /// </devdoc>
        protected bool HasChildViewState {
            get {
                return ((_occasionalFields != null) &&
                        (_occasionalFields.ControlsViewState != null) &&
                        (_occasionalFields.ControlsViewState.Count > 0));
            }
        }
 
 
        /// <devdoc>
        /// Sets initial focus on the control
        /// </devdoc>
        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 (AdapterInternal == null || savedState.Second == null) {
                return;
            }
            AdapterInternal.LoadAdapterControlState(savedState.Second);
        }
 
 
        /// <devdoc>
        /// Load the control state, which is the essential state information needed even if view state is disabled.
        /// </devdoc>
        protected internal virtual void LoadControlState(object savedState) {
        }
 
 
        /// <devdoc>
        ///    <para>Restores the view state information from a previous page
        ///       request that was saved by the Control.SavedState method.</para>
        /// </devdoc>
        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);
                }
 
                object validateRequestModeValue = ViewState["ValidateRequestMode"];
                if (validateRequestModeValue != null) {
                    flags[validateRequestMode, validateRequestModeOffset] = (int)validateRequestModeValue;
                    flags.Set(validateRequestModeDirty);
                }
            }
        }
 
        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) && (AdapterInternal != null)) {
                        AdapterInternal.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));
            }
        }
 
 
        /// <devdoc>
        /// <para>
        ///   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
        /// </para>
        /// </devdoc>
        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;
        }
 
 
        /// <devdoc>
        /// <para>
        ///   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
        /// </para>
        /// </devdoc>
        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;
        }
 
 
        /// <devdoc>
        /// <para>Raises the <see langword='Load'/>
        /// event. This notifies the control that it should perform any work that needs to
        /// occur for each page request.</para>
        /// </devdoc>
        protected internal virtual void OnLoad(EventArgs e) {
            if(HasEvents()) {
                EventHandler handler = _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 (AdapterInternal != null) {
                    AdapterInternal.OnLoad(EventArgs.Empty);
                }
                else {
                    OnLoad(EventArgs.Empty);
                }
            }
 
            // Call Load on all our children
            if (_controls != null) {
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    _controls[i].LoadRecursive();
                }
 
                _controls.SetCollectionReadOnly(oldmsg);
            }
 
            if (_controlState < ControlState.Loaded)
                _controlState = ControlState.Loaded;
        }
 
        // Same as LoadRecursive, but has an async point immediately after the call to this.OnLoad.
        internal async Task LoadRecursiveAsync(Page page) {
            // Only make the actual call if it hasn't already happened (ASURT 111303)
            if (_controlState < ControlState.Loaded) {
                using (page.Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
                    if (AdapterInternal != null) {
                        AdapterInternal.OnLoad(EventArgs.Empty);
                    }
                    else {
                        OnLoad(EventArgs.Empty);
                    }
                    await page.GetWaitForPreviousStepCompletionAwaitable();
                }
            }
 
            // Call Load on all our children
            if (_controls != null) {
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    _controls[i].LoadRecursive();
                }
 
                _controls.SetCollectionReadOnly(oldmsg);
            }
 
            if (_controlState < ControlState.Loaded)
                _controlState = ControlState.Loaded;
        }
 
        /// <devdoc>
        /// <para>Raises the <see langword='PreRender'/> event. This method uses event arguments
        ///    to pass the event data to the control.</para>
        /// </devdoc>
        protected internal virtual void OnPreRender(EventArgs e) {
            if(HasEvents()) {
                EventHandler handler = _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 (AdapterInternal != null) {
                    AdapterInternal.OnPreRender(EventArgs.Empty);
                }
                else {
                    OnPreRender(EventArgs.Empty);
                }
 
                if (_controls != null) {
                    string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                    int controlCount = _controls.Count;
                    for (int i=0; i < controlCount; i++) {
                        _controls[i].PreRenderRecursiveInternal();
                    }
                    _controls.SetCollectionReadOnly(oldmsg);
                }
            }
            _controlState = ControlState.PreRendered;
        }
 
        // Same as PreRenderRecursive, but has an async point after the call to this.OnPreRender.
        internal async Task PreRenderRecursiveInternalAsync(Page page) {
            // 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);
                if (AppSettings.EnableAsyncModelBinding) {
                    using (page.Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
                        EnsureChildControls();
                        await page.GetWaitForPreviousStepCompletionAwaitable();
                    }
                }
                else {
                    EnsureChildControls();
                }                
 
                using (page.Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
                    if (AdapterInternal != null) {
                        AdapterInternal.OnPreRender(EventArgs.Empty);
                    }
                    else {
                        OnPreRender(EventArgs.Empty);
                    }
                    await page.GetWaitForPreviousStepCompletionAwaitable();
                }
 
                if (_controls != null) {
                    string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                    int controlCount = _controls.Count;
                    for (int i = 0; i < controlCount; i++) {
                        if (AppSettings.EnableAsyncModelBinding) {
                            // To make sure every OnPreRender is awaited so that _controlState
                            // would not be set to ControlState.PreRendered until the control is
                            // really PreRendered
                            await _controls[i].PreRenderRecursiveInternalAsync(page);
                        }
                        else {
                            _controls[i].PreRenderRecursiveInternal();
                        }
                    }
 
                    _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
         */
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Gathers information about the control and delivers it to the <see cref='System.Web.UI.Page.Trace'/>
        /// property to be displayed when tracing is enabled for the page.</para>
        /// </devdoc>
        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 (_controls != null) {
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++) {
                    _controls[i].BuildProfileTree(UniqueID, calcViewState);
                }
            }
        }
 
 
        internal object SaveControlStateInternal() {
            object controlState = SaveControlState();
            object adapterControlState = null;
            if (AdapterInternal != null) {
                adapterControlState = AdapterInternal.SaveAdapterControlState();
            }
            if (controlState != null || adapterControlState != null) {
                return new Pair(controlState, adapterControlState);
            }
            return null;
        }
 
 
        /// <devdoc>
        /// Save the control state, which is the essential state information needed even if view state is disabled.
        /// </devdoc>
        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.
 
        /// <devdoc>
        ///    <para>
        ///       Saves view state for use with a later <see cref='System.Web.UI.Control.LoadViewState'/>
        ///       request.
        ///    </para>
        /// </devdoc>
        protected virtual object SaveViewState() {
            // Save values cached out of view state
            if (flags[visibleDirty]) {
                ViewState["Visible"] = !flags[invisible];
            }
            if (flags[validateRequestModeDirty]) {
                ViewState["ValidateRequestMode"] = (int)ValidateRequestMode;
            }
            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(ViewStateMode inheritedMode) {
            if (flags[disableViewState])
                return null;
 
            bool saveThisState;
            if (flags[viewStateNotInherited]) {
                if (flags[viewStateMode]) {
                    saveThisState = true;
                    inheritedMode = ViewStateMode.Enabled;
                }
                else {
                    saveThisState = false;
                    inheritedMode = ViewStateMode.Disabled;
                }
            }
            else {
                saveThisState = (inheritedMode == ViewStateMode.Enabled);
            }
 
            object adapterState = null;
            object controlSavedState = null;
 
            if (saveThisState) {
                if (AdapterInternal != null) {
                    adapterState = AdapterInternal.SaveAdapterViewState();
                }
                controlSavedState = SaveViewState();    
            }
 
            ArrayList childStates = null;
            if (HasControls()) {
                ControlCollection occasionalFieldControls = _controls;
                int occasionalFieldControlCount = occasionalFieldControls.Count;
 
                bool useId = LoadViewStateByID;
                for (int i = 0; i < occasionalFieldControlCount; i++) {
                    Control child = occasionalFieldControls[i];
                    object childState = child.SaveViewStateRecursive(inheritedMode);
                    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 (AdapterInternal != 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;
        }
 
 
        /// <devdoc>
        /// <para>Outputs control content to a provided HTMLTextWriter
        /// output stream.</para>
        /// </devdoc>
        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 = _controls;
            RenderChildrenInternal(writer, children);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public virtual void RenderControl(HtmlTextWriter writer) {
            //use the Adapter property to ensure it is resolved
            RenderControl(writer, Adapter);
        }
 
        /// <devdoc>
        ///    <para>Used for MobilePage implementation.</para>
        /// </devdoc>
        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);
                }
            }
            else {
                TraceNonRenderingControlInternal(writer);
            }
        }
 
        private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) {
            try {
                BeginRenderTracing(writer, this);
 
                if (adapter != null) {
                    // 
                    adapter.BeginRender(writer);
                    adapter.Render(writer);
                    adapter.EndRender(writer);
                }
                else {
                    Render(writer);
                }
            }
            finally {
                EndRenderTracing(writer, this);
            }
        }
 
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected internal virtual void OnUnload(EventArgs e) {
            if(HasEvents()) {
                EventHandler handler = _events[EventUnload] as EventHandler;
                if (handler != null) {
                    handler(this, e);
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para>Enables a control to perform final cleanup.</para>
        /// </devdoc>
        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;
            }
 
            if (_events != null) {
                _events.Dispose();
                _events = 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 (_controls != null) {
                string oldmsg = _controls.SetCollectionReadOnly(SR.Parent_collections_readonly);
 
                int controlCount = _controls.Count;
                for (int i = 0; i < controlCount; i++)
                    _controls[i].UnloadRecursive(dispose);
 
                _controls.SetCollectionReadOnly(oldmsg);
            }
 
            if (AdapterInternal != null) {
                AdapterInternal.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;
            }
        }
 
 
        /// <devdoc>
        ///    <para>Assigns an sources of the event and its information up the page control
        ///       hierarchy until they reach the top of the control tree. </para>
        /// </devdoc>
        protected void RaiseBubbleEvent(object source, EventArgs args) {
            Control currentTarget = Parent;
            while (currentTarget != null) {
                if (currentTarget.OnBubbleEvent(source, args)) {
                    return;
                }
                currentTarget = currentTarget.Parent;
            }
        }
 
 
        /// <devdoc>
        ///    <para>Determines whether the event for the control should be passed up the page's
        ///       control hierarchy.</para>
        /// </devdoc>
        protected virtual bool OnBubbleEvent(object source, EventArgs args) {
            return false;
        }
 
 
        // Members related to being a container
 
 
        /// <devdoc>
        ///    <para> Gets a ControlCollection object that represents the child controls for a specified control in the
        ///       UI hierarchy.</para>
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebSysDescription(SR.Control_Controls)
        ]
        public virtual ControlCollection Controls {
            get {
                if (_controls == null) {
                    _controls = CreateControlCollection();
                }
                return _controls;
            }
        }
 
        [
        WebCategory("Behavior"),
        WebSysDescription(SR.Control_ValidateRequestMode),
        DefaultValue(ValidateRequestMode.Inherit)
        ]
        public virtual ValidateRequestMode ValidateRequestMode {
            get {
                return (ValidateRequestMode)flags[validateRequestMode, validateRequestModeOffset];
            }
            set {
                SetValidateRequestModeInternal(value, setDirty: true);
            }
        }
 
        internal void SetValidateRequestModeInternal(UI.ValidateRequestMode value, bool setDirty) {
            if (value < ValidateRequestMode.Inherit || value > ValidateRequestMode.Enabled) {
                throw new ArgumentOutOfRangeException("value");
            }
 
            int oldValue = flags[validateRequestMode, validateRequestModeOffset];
            if (setDirty && (oldValue != (int)value)) {
                flags.Set(validateRequestModeDirty);
            }
 
            flags[validateRequestMode, validateRequestModeOffset] = (int)value;
        }
 
        internal bool CalculateEffectiveValidateRequest() {
            RuntimeConfig config = RuntimeConfig.GetConfig();
            HttpRuntimeSection runtimeSection = config.HttpRuntime;
            if (runtimeSection.RequestValidationMode >= VersionUtil.Framework45) {
                Control c = this;
                while (c != null) {
                    ValidateRequestMode mode = c.ValidateRequestMode;
                    if (mode != ValidateRequestMode.Inherit) {
                        return mode == ValidateRequestMode.Enabled;
                    }
                    c = c.Parent;
                }
            }
            return true;
        }
 
 
        /// <devdoc>
        ///    <para>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.</para>
        /// </devdoc>
        [
        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.
 
        /// <devdoc>
        /// <para>Indicates whether the <see cref='System.Web.UI.StateBag'/> object is case-insensitive.</para>
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)        
        ]
        protected virtual bool ViewStateIgnoresCase {
            get {
                return false;
            }
        }
 
 
        /// <devdoc>
        /// </devdoc>
        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._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();
                    }
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected virtual ControlCollection CreateControlCollection() {
            return new ControlCollection(this);
        }
 
 
        /// <devdoc>
        ///    <para>
        ///       Notifies any controls that use composition-based implementation to create any
        ///       child controls they contain in preperation for postback or rendering.
        ///    </para>
        /// </devdoc>
        protected internal virtual void CreateChildControls() {
        }
 
 
 
        /// <devdoc>
        ///    <para>Indicates whether the control's child controls have been created.</para>
        /// </devdoc>
        protected bool ChildControlsCreated {
            get {
                return flags[controlsCreated];
            }
            set {
                if (!value && flags[controlsCreated]) {
                    Controls.Clear();
                }
                if(value) {
                    flags.Set(controlsCreated);
                }
                else {
                    flags.Clear(controlsCreated);
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para>Make a URL absolute using the AppRelativeTemplateSourceDirectory.  The returned URL is for
        ///        client use, and will contain the session cookie if appropriate.</para>
        /// </devdoc>
        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);
        }
 
 
        /// <devdoc>
        ///    <para> 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).</para>
        /// </devdoc>
        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
            url = HttpUtility.UrlPathEncode(UrlPath.MakeRelative(baseRequestDir, url));
            Debug.Trace("ClientUrl", "*** ResolveClientUrl (" + relativeUrl + ") --> " + url + " ***");
            return 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, _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);
                }
            }
        }
 
 
        /// <devdoc>
        ///    <para>Searches the current naming container for a control with
        ///       the specified <paramref name="id"/> .</para>
        /// </devdoc>
        public virtual Control FindControl(String id) {
            return FindControl(id, 0);
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        ///    <para>Searches the current naming container for a control with the specified
        ///    <paramref name="id"/> and an offset to aid in the
        ///       search.</para>
        /// </devdoc>
        protected virtual Control FindControl(String id, int pathOffset) {
            // DevDiv #338426 - Since this is a recursive function, malicious clients can send us an id
            // which causes a very deep stack dive, resulting in SO (which terminates the worker process).
            // We avoid this via the following call, which at the time of this writing ensures that at
            // least 50% of the available stack remains. The check is very quick: < 1 microsecond.
            RuntimeHelpers.EnsureSufficientExecutionStack();
 
            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 doesn't ensures _occasionalFields != null
            if (HasControls()) {
                EnsureOccasionalFields();
                if (_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);
        }
 
        internal Control FindControlFromPageIfNecessary(string id) {
            Control c = FindControl(id);
            // Find control from the page if it's a hierarchical ID.
            // Dev11 bug 19915
            if (c == null && Page != null) {
                char[] findControlSeparators = { ID_SEPARATOR, LEGACY_ID_SEPARATOR };
                if (id.IndexOfAny(findControlSeparators) != -1) {
                    c = Page.FindControl(id);
                }
            }
            return c;
        }
 
        /*
         * Called when the controls of a naming container are cleared.
         */
        internal void ClearNamingContainer() {
            Debug.Assert(this is INamingContainer);
 
            EnsureOccasionalFields();
            _occasionalFields.NamedControlsID = 0;
            DirtyNameTable();
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// </devdoc>
        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        protected virtual IDictionary GetDesignModeState() {
            ControlRareFields rareFields = RareFieldsEnsured;
            if (rareFields.DesignModeState == null) {
                rareFields.DesignModeState = new HybridDictionary();
            }
            return rareFields.DesignModeState;
        }
 
 
        /// <devdoc>
        ///    <para>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 <see cref='System.Web.UI.ControlCollection'/> class, on the <see cref='System.Web.UI.Control.Controls'/>
        ///       property.</para>
        /// </devdoc>
        public virtual bool HasControls() {
            return _controls != null && _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.
         */
 
        /// <devdoc>
        ///    <para>Determines if the container holds literal content only.
        ///       When this method returns <see langword='true'/>
        ///       , the container collection only holds a single literal control. The
        ///       content is then passed to the requesting browser as HTML.</para>
        /// </devdoc>
        protected bool IsLiteralContent() {
            return (_controls != null) && (_controls.Count == 1) &&
            ((_controls[0] is LiteralControl));
        }
 
 
        /// <devdoc>
        ///    <para>Determines if view state changes to the
        ///    <see langword='Control'/>
        ///    are being saved. </para>
        /// </devdoc>
        protected bool IsTrackingViewState {
            get {
                return flags[marked];
            }
        }
 
 
        /// <devdoc>
        ///    <para>Turns on tracking of view state changes to the control
        ///       so that they can be stored in the <see langword='StateBag'/>
        ///       object.</para>
        /// </devdoc>
        protected virtual void TrackViewState() {
            if (_viewState != null)
                _viewState.TrackViewState();
 
            flags.Set(marked);
        }
 
 
        /// <devdoc>
        ///    <para>Checks that the control contains child controls; if it does not, it creates
        ///       them. This includes any literal content being parsed as a <see cref='System.Web.UI.LiteralControl'/>
        ///       object. </para>
        /// </devdoc>
        protected virtual void EnsureChildControls() {
            if (!ChildControlsCreated && !flags[creatingControls]) {
                flags.Set(creatingControls);
                try {
                    ResolveAdapter();
                    if (AdapterInternal != null) {
                        AdapterInternal.CreateChildControls();
                    }
                    else {
                        CreateChildControls();
                    }
 
                    // Only set ChildControlsCreated = true if CreateChildControls() did not throw
                    // an exception (VSWhidbey 465798).
                    ChildControlsCreated = true;
                }
                finally {
                    flags.Clear(creatingControls);
                }
            }
        }
 
        /// <devdoc>
        /// 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.
        /// </devdoc>
        internal void SetControlBuilder(ControlBuilder controlBuilder) {
            RareFieldsEnsured.ControlBuilder = controlBuilder;
        }
 
 
        /// <devdoc>
        /// </devdoc>
        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 template source virtual directory 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)) {
                if (control._occasionalFields != null) {
                    control._occasionalFields.TemplateSourceVirtualDirectory = null;
                }
            }
 
            if (control._occasionalFields != null ) {
                control._occasionalFields.TemplateControl = null;
            }
 
            control.flags.Clear(mustRenderID);
            control.ClearCachedUniqueIDRecursive();
        }
 
        internal void SetDesignMode() {
            flags.Set(designMode);
            flags.Set(designModeChecked);
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// </devdoc>
        protected virtual void SetDesignModeState(IDictionary data) {
        }
 
        // Set the delegate to the render method
 
        /// <internalonly/>
        /// <devdoc>
        ///    <para>Assigns any event handler delegates for the control to match the parameters
        ///       defined in the <see cref='System.Web.UI.RenderMethod'/>. </para>
        /// </devdoc>
        [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);
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        ///    <para>Returns whether the control contains any data binding logic. This method is
        ///       only accessed by RAD designers.</para>
        /// </devdoc>
        bool IDataBindingsAccessor.HasDataBindings {
            get {
                return ((RareFields != null) && (RareFields.DataBindings != null) && (RareFields.DataBindings.Count != 0));
            }
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Indicates a collection of all data bindings on the control. This property is
        /// read-only.</para>
        /// </devdoc>
        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.
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Notifies the control that an element, XML or HTML, was parsed, and adds it to
        /// the control.</para>
        /// </devdoc>
        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 = AdapterInternal as IPostBackDataHandler;
                if(pbdh != null)
                    return pbdh;
                pbdh = this as IPostBackDataHandler;
                return pbdh;
            }
        }
 
        internal IPostBackEventHandler PostBackEventHandler {
            get {
                IPostBackEventHandler pbeh = AdapterInternal as IPostBackEventHandler;
                if(pbeh != null)
                    return pbeh;
                pbeh = this as IPostBackEventHandler;
                return pbeh;
            }
        }
 
        /// <summary>
        /// This method is used for design-time tracing of rendering data.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected void BeginRenderTracing(TextWriter writer, object traceObject) {
            RenderTraceListener.CurrentListeners.BeginRendering(writer, traceObject);
        }
 
        /// <summary>
        /// This method is used for design-time tracing of rendering data.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected void EndRenderTracing(TextWriter writer, object traceObject) {
            RenderTraceListener.CurrentListeners.EndRendering(writer, traceObject);
        }
 
        private void TraceNonRenderingControlInternal(TextWriter writer) {
            BeginRenderTracing(writer, this);
            EndRenderTracing(writer, this);
        }
 
        /// <summary>
        /// This method is used for design-time tracing of rendering data.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void SetTraceData(object traceDataKey, object traceDataValue) {
            SetTraceData(this, traceDataKey, traceDataValue);
        }
 
        /// <summary>
        /// This method is used for design-time tracing of rendering data.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void SetTraceData(object tracedObject, object traceDataKey, object traceDataValue) {
            RenderTraceListener.CurrentListeners.SetTraceData(tracedObject, traceDataKey, traceDataValue);
        }
 
        #region IControlDesignerAccessor implementation
 
        /// <internalonly/>
        IDictionary IControlDesignerAccessor.UserData {
            get {
                ControlRareFields rareFields = RareFieldsEnsured;
                if (rareFields.ControlDesignerAccessorUserData == null) {
                    rareFields.ControlDesignerAccessorUserData = new HybridDictionary();
                }
                return rareFields.ControlDesignerAccessorUserData;
            }
        }
 
        /// <internalonly/>
        /// <devdoc>
        /// </devdoc>
        IDictionary IControlDesignerAccessor.GetDesignModeState() {
            return GetDesignModeState();
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// </devdoc>
        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
 
        /// <internalonly/>
        /// <devdoc>
        /// A reference to the ControlBuilder that was used to construct this control (if there was one)
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        ControlBuilder IControlBuilderAccessor.ControlBuilder {
            get {
                return RareFields != null ? RareFields.ControlBuilder : null;
            }
        }
        #endregion IControlBuilderAccessor implementation
 
        #region IExpressionsAccessor
 
 
        /// <internalonly/>
        bool IExpressionsAccessor.HasExpressions {
            get {
                if (RareFields == null) {
                    return false;
                }
                ExpressionBindingCollection expressions = RareFields.ExpressionBindings;
                return ((expressions != null) && (expressions.Count > 0));
            }
        }
 
 
        /// <internalonly/>
        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 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 Version RenderingCompatibility;
            public RouteCollection RouteCollection;
            public ControlAdapter Adapter;
 
            public void Dispose() {
                //do not null out for backwards compat, VSWhidbey 475940
                //Site = null;
                //RenderMethod = null;
                //DataBindings = null;
                //OwnerControl = null;
                //ExpressionBindings = null;
                //Adapter = null;
                ControlBuilder = null;
                if (OwnerControl != null)
                {
                    OwnerControl.Dispose();
                }
                ControlDesignerAccessorUserData = null;
                DesignModeState = null;
                RenderingCompatibility = null;
                RouteCollection = null;
            }
        }
 
        private sealed class OccasionalFields : IDisposable {
            internal OccasionalFields() {
            }
 
            public string SkinId;
            public IDictionary ControlsViewState;
            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 TemplateControl TemplateControl;
            public VirtualPath TemplateSourceVirtualDirectory;
 
            public void Dispose() {
                if (RareFields != null) {
                    RareFields.Dispose();
                }
 
                ControlsViewState = null;
                //do not null out for backwards compat, VSWhidbey 475940
                //NamedControls = null;
                //UniqueIDPrefix = null;
                //TemplateControl = null;
                //TemplateSourceVirtualDirectory = null;
            }
        }
    }
}