ControlBuilder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / xsp / System / Web / UI / ControlBuilder.cs / 10 / ControlBuilder.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 
namespace System.Web.UI {
    using System; 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Runtime.Serialization.Formatters;
    using System.Security.Permissions; 
    using System.Text; 
    using System.Text.RegularExpressions;
    using System.Resources; 
    using System.Web;
    using System.Web.Compilation;
    using System.Web.RegularExpressions;
    using System.Web.UI.HtmlControls; 
    using System.Web.UI.WebControls;
    using System.Web.Util; 
    using System.CodeDom; 

    ///  
    /// Implementation of a generic control builder used by all controls and child objects
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 
    public class ControlBuilder {
 
        public readonly static string DesignerFilter = "__designer"; 

#if DEBUG 
        private bool _initCalled;
#endif

        // Parses a databinding expression (e.g. <%# i+1 %> 
        private readonly static Regex databindRegex = new DataBindRegex();
        internal readonly static Regex expressionBuilderRegex = new ExpressionBuilderRegex(); 
        private readonly static Regex bindExpressionRegex = new BindExpressionRegex(); 
        private readonly static Regex bindParametersRegex = new BindParametersRegex();
        private readonly static Regex evalExpressionRegex = new EvalExpressionRegex(); 
        private readonly static Regex formatStringRegex = new FormatStringRegex();

        private Type _controlType;
        private string _tagName; 
        private string _skinID;
        private ArrayList _subBuilders; 
        private ControlBuilderParseTimeData _parseTimeData; 
        private IServiceProvider _serviceProvider;
 
        //
        private ArrayList _eventEntries;
        private ArrayList _simplePropertyEntries;
        private ArrayList _complexPropertyEntries; 
        private ArrayList _templatePropertyEntries;
        private ArrayList _boundPropertyEntries; 
 
        private PropertyDescriptor _bindingContainerDescriptor;
 
        //


        // const masks into the BitVector32 
        private const int parseComplete                 = 0x00000001;
        private const int needsTagAttributeComputed     = 0x00000002; 
        private const int needsTagAttribute             = 0x00000004; 
        private const int doneInitObjectOptimizations   = 0x00000008;
        private const int isICollection                 = 0x00000010; 
        private const int isIParserAccessor             = 0x00000020;
        private const int hasFilteredSimpleProps        = 0x00000040;
        private const int hasFilteredComplexProps       = 0x00000080;
        private const int hasFilteredTemplateProps      = 0x00000100; 
        private const int hasFilteredBoundProps         = 0x00000200;
        private const int hasTwoWayBoundProps           = 0x00000400; 
        private const int triedFieldToControlBinding    = 0x00000800; 
        private const int hasFieldToControlBinding      = 0x00001000;
        private const int controlTypeIsControl          = 0x00002000; // Indicates that the type specified in _controlType derives from Control 
        private const int entriesSorted                 = 0x00004000;
        private const int applyTheme                    = 0x00008000;
        #pragma warning disable 0649
        private SimpleBitVector32 flags; 
        #pragma warning restore 0649
 
 
        /// 
        ///  
        public virtual Type BindingContainerType {
            get {
                if (NamingContainerBuilder == null) {
                    return typeof(System.Web.UI.Control); 
                }
 
                Type ctrlType = NamingContainerBuilder.ControlType; 

                Debug.Assert(ctrlType != null, "Control type is null."); 
                Debug.Assert(typeof(INamingContainer).IsAssignableFrom(ctrlType), String.Format(CultureInfo.InvariantCulture, "NamingContainerBuilder.Control type {0} is not an INamingContainer", ctrlType.FullName));

                // Recursively lookup if the NamingContainerBuilder.ControlType is an INonBindingContainer
                if (typeof(INonBindingContainer).IsAssignableFrom(ctrlType)) { 
                    return NamingContainerBuilder.BindingContainerType;
                } 
 
                return NamingContainerBuilder.ControlType;
            } 
        }

        internal ICollection EventEntries {
            get { 
                // If there are no entries, return a static empty collection
                if (_eventEntries == null) 
                    return EmptyCollection.Instance; 

                return _eventEntries; 
            }
        }

        private ArrayList EventEntriesInternal { 
            get {
                // Create the ArrayList on demand 
                if (_eventEntries == null) 
                    _eventEntries = new ArrayList();
 
                return _eventEntries;
            }
        }
 
        internal ICollection SimplePropertyEntries {
            get { 
                // If there are no entries, return a static empty collection 
                if (_simplePropertyEntries == null)
                    return EmptyCollection.Instance; 

                return _simplePropertyEntries;
            }
        } 

        internal ArrayList SimplePropertyEntriesInternal { 
            get { 
                // Create the ArrayList on demand
                if (_simplePropertyEntries == null) 
                    _simplePropertyEntries = new ArrayList();

                return _simplePropertyEntries;
            } 
        }
 
        internal ICollection ComplexPropertyEntries { 
            get {
                // If there are no entries, return a static empty collection 
                if (_complexPropertyEntries == null)
                    return EmptyCollection.Instance;

                return _complexPropertyEntries; 
            }
        } 
 
        private ArrayList ComplexPropertyEntriesInternal {
            get { 
                // Create the ArrayList on demand
                if (_complexPropertyEntries == null)
                    _complexPropertyEntries = new ArrayList();
 
                return _complexPropertyEntries;
            } 
        } 

        internal ICollection TemplatePropertyEntries { 
            get {
                // If there are no entries, return a static empty collection
                if (_templatePropertyEntries == null)
                    return EmptyCollection.Instance; 

                return _templatePropertyEntries; 
            } 
        }
 
        private ArrayList TemplatePropertyEntriesInternal {
            get {
                // Create the ArrayList on demand
                if (_templatePropertyEntries == null) 
                    _templatePropertyEntries = new ArrayList();
 
                return _templatePropertyEntries; 
            }
        } 

        internal ICollection BoundPropertyEntries {
            get {
                // If there are no entries, return a static empty collection 
                if (_boundPropertyEntries == null)
                    return EmptyCollection.Instance; 
 
                return _boundPropertyEntries;
            } 
        }

        private ArrayList BoundPropertyEntriesInternal {
            get { 
                // Create the ArrayList on demand
                if (_boundPropertyEntries == null) 
                    _boundPropertyEntries = new ArrayList(); 

                return _boundPropertyEntries; 
            }
        }

        internal bool HasFilteredBoundEntries { 
            get {
                return flags[hasFilteredBoundProps]; 
            } 
        }
 
        internal bool IsNoCompile {
            get {
                return flags[parseComplete];
            } 
        }
 
        internal string SkinID { 
            get {
                return _skinID; 
            }
            set {
                _skinID = value;
            } 
        }
 
 
        /// 
        /// Return the type of the control that this builder creates 
        /// 
        public Type ControlType {
            get {
                return _controlType; 
            }
        } 
 

        public IFilterResolutionService CurrentFilterResolutionService { 
            get {
                if (ServiceProvider != null) {
                    return (IFilterResolutionService)ServiceProvider.GetService(typeof(IFilterResolutionService));
                } 
                else {
                    // If there is no ServiceProvider, use the TemplateControl ( 
                    return TemplateControl; 
                }
            } 
        }


        ///  
        /// Return the type that will be used by codegen to declare the control
        ///  
        public virtual Type DeclareType { 
            get {
                return _controlType; 
            }
        }

        ///  
        /// Gets the IDesignerHost if we are in design mode. This is used to load
        /// config through IWebApplication rather than the RuntimeConfig object. 
        ///  
        private IDesignerHost DesignerHost {
            get { 
                if (InDesigner && ParseTimeData != null) {
                    TemplateParser parser = ParseTimeData.Parser;
                    if (parser != null) {
                        return parser.DesignerHost; 
                    }
                } 
                return null; 
            }
        } 

        /// 
        ///
        ///  
        private ControlBuilder DefaultPropertyBuilder {
            get { 
                return ParseTimeData.DefaultPropertyBuilder; 
            }
        } 


        public IThemeResolutionService ThemeResolutionService {
            get { 
                if (ServiceProvider != null) {
                    return (IThemeResolutionService)ServiceProvider.GetService(typeof(IThemeResolutionService)); 
                } 
                else {
                    // If there is no ServiceProvider, use the TemplateControl ( 
                    return TemplateControl as IThemeResolutionService;
                }
            }
        } 

        ///  
        /// 
        /// 
        private EventDescriptorCollection EventDescriptors { 
            get {
                if (ParseTimeData.EventDescriptors == null) {
                    ParseTimeData.EventDescriptors = TypeDescriptor.GetEvents(_controlType);
                } 

                return ParseTimeData.EventDescriptors; 
            } 
        }
 
        internal string Filter {
            get {
                return ParseTimeData.Filter;
            } 
            set {
                ParseTimeData.Filter = value; 
            } 
        }
 

        /// 
        ///
        ///  
        protected bool FChildrenAsProperties {
            get { 
                return ParseTimeData.ChildrenAsProperties; 
            }
        } 


        /// 
        ///    [To be supplied.] 
        /// 
        protected bool FIsNonParserAccessor { 
            get { 
                return ParseTimeData.IsNonParserAccessor;
            } 
        }


        ///  
        ///    [To be supplied.]
        ///  
        public bool HasAspCode { 
            get {
                return ParseTimeData.HasAspCode; 
            }
        }

        /* 
         * Return the ID of the control that this builder creates
         */ 
 
        /// 
        ///    [To be supplied.] 
        /// 
        public string ID {
            get {
                return ParseTimeData.ID; 
            }
            set { 
                ParseTimeData.ID = value; 
            }
        } 

        internal bool IsGeneratedID {
            get {
                return ParseTimeData.IsGeneratedID; 
            }
            set { 
                ParseTimeData.IsGeneratedID = value; 
            }
        } 

        private bool IgnoreControlProperty {
            get {
                return ParseTimeData.IgnoreControlProperties; 
            }
        } 
 

        ///  
        ///     InDesigner property gets used by control builders so that they can behave
        ///         differently if needed. 
        /// 
        protected bool InDesigner { 
            get {
                // If  we're in no-compile page mode, return false 
                if (IsNoCompile) 
                    return false;
 
                // Simply return null when called without a Parser.
                // This is in the codepath from TemplateBuilder.NeedsTagInnerText()
                // to determine designer source code preservation behavior by tools.
                if (Parser == null) 
                    return false;
 
                return Parser.FInDesigner; 
            }
        } 


        /// 
        ///     InPageTheme property indicates if the control builder is used to generate page themes. 
        /// 
        protected bool InPageTheme { 
            get { 
                return Parser is PageThemeParser;
            } 
        }

        internal bool IsControlSkin {
            get { 
                return ParentBuilder is FileLevelPageThemeBuilder;
            } 
        } 

        ///  
        ///
        /// 
        private bool IsHtmlControl {
            get { 
                return ParseTimeData.IsHtmlControl;
            } 
        } 

        ///  
        /// The source file line number at which this builder is defined
        /// 
        internal int Line {
            get { 
                return ParseTimeData.Line;
            } 
            set { 
                ParseTimeData.Line = value;
            } 
        }

        public bool Localize {
            get { 
                if (ParseTimeData != null) {
                    return ParseTimeData.Localize; 
                } 

                return true; 
            }
        }

        ///  
        ///
        ///  
        private ControlBuilder NamingContainerBuilder { 
            get {
                if (ParseTimeData.NamingContainerSearched) { 
                    return ParseTimeData.NamingContainerBuilder;
                }

                if (ParentBuilder == null || ParentBuilder.ControlType == null) { 
                    ParseTimeData.NamingContainerBuilder = null;
                } 
                else if (typeof(INamingContainer).IsAssignableFrom(ParentBuilder.ControlType)) { 
                    ParseTimeData.NamingContainerBuilder = ParentBuilder;
                } 
                else {
                    ParseTimeData.NamingContainerBuilder = ParentBuilder.NamingContainerBuilder;
                }
 
                ParseTimeData.NamingContainerSearched = true;
                return ParseTimeData.NamingContainerBuilder; 
            } 
        }
 

        /// 
        /// 
        /// Return the type of the naming container of the control that this builder creates 
        /// 
        public Type NamingContainerType { 
            get { 
                if (NamingContainerBuilder == null) {
                    return typeof(System.Web.UI.Control); 
                }

                return NamingContainerBuilder.ControlType;
            } 
        }
 
        ///  
        ///
        ///  
        internal CompilationMode CompilationMode {
            get {
                return Parser.CompilationMode;
            } 
        }
 
        ///  
        ///
        ///  
        internal ControlBuilder ParentBuilder {
            get {
                return ParseTimeData.ParentBuilder;
            } 
        }
 
 
        /// 
        /// 
        /// 
        protected internal TemplateParser Parser {
            get {
                return ParseTimeData.Parser; 
            }
        } 
 
        /// 
        /// 
        /// 
        private ControlBuilderParseTimeData ParseTimeData {
            get {
                if (_parseTimeData == null) { 
                    if (IsNoCompile) {
                        throw new InvalidOperationException(SR.GetString(SR.ControlBuilder_ParseTimeDataNotAvailable)); 
                    } 

                    _parseTimeData = new ControlBuilderParseTimeData(); 
                }

                return _parseTimeData;
            } 
        }
 
        ///  
        ///
        ///  
        private PropertyDescriptorCollection PropertyDescriptors {
            get {
                if (ParseTimeData.PropertyDescriptors == null) {
                    ParseTimeData.PropertyDescriptors = TypeDescriptor.GetProperties(_controlType); 
                }
 
                return ParseTimeData.PropertyDescriptors; 
            }
        } 

        private StringSet PropertyEntries {
            get {
                if (ParseTimeData.PropertyEntries == null) { 
                    ParseTimeData.PropertyEntries = new CaseInsensitiveStringSet();
                } 
 
                return ParseTimeData.PropertyEntries;
            } 
        }

        /// 
        /// 
        /// 
        internal ArrayList SubBuilders { 
            get { 
                if (_subBuilders == null) {
                    _subBuilders = new ArrayList(); 
                }

                return _subBuilders;
            } 
        }
 
        public IServiceProvider ServiceProvider { 
            get {
                return _serviceProvider; 
            }
        }

        ///  
        ///
        ///  
        private bool SupportsAttributes { 
            get {
                return ParseTimeData.SupportsAttributes; 
            }
        }

 
        /// 
        ///    [To be supplied.] 
        ///  
        public string TagName {
            get { 
                return _tagName;
            }
        }
 
        /// 
        /// The name of the source file in which this builder is defined 
        ///  
        internal VirtualPath VirtualPath {
            get { 
                return ParseTimeData.VirtualPath;
            }
            set {
                ParseTimeData.VirtualPath = value; 
            }
        } 
 
        internal string VirtualPathString {
            get { 
                return System.Web.VirtualPath.GetVirtualPathString(VirtualPath);
            }
        }
 
        /// 
        /// The template control that hosts the current control. For example, it is the usercontrol for controls defined in a usercontrol file. 
        /// This property is available only in non-compiled cases. 
        /// 
        internal TemplateControl TemplateControl { 
            get {
                HttpContext context = HttpContext.Current;
                if (context == null) {
                    return null; 
                }
 
                return context.TemplateControl; 
            }
        } 

        private void AddBoundProperty(string filter, string name, string expressionPrefix,
            string expression, ExpressionBuilder expressionBuilder, object parsedExpressionData, string fieldName, string formatString, bool twoWayBound) {
            AddBoundProperty(filter, name, expressionPrefix, expression, expressionBuilder, parsedExpressionData, false, fieldName, formatString, twoWayBound); 
        }
 
        ///  
        ///
        ///  
        private void AddBoundProperty(string filter, string name, string expressionPrefix,
            string expression, ExpressionBuilder expressionBuilder, object parsedExpressionData, bool generated, string fieldName,
            string formatString, bool twoWayBound) {
 
            Debug.Assert(!String.IsNullOrEmpty(name));
 
            string controlID = ParseTimeData.ID; 

            // Get the IDesignerHost in case we need it to find ExpressionBuilders 
            IDesignerHost host = DesignerHost;

            if (String.IsNullOrEmpty(expressionPrefix)) {
                // This is a databinding entry 
                if (String.IsNullOrEmpty(controlID)) {
                    if (CompilationMode == CompilationMode.Never) { 
                        throw new HttpException(SR.GetString(SR.NoCompileBinding_requires_ID, _controlType.Name, fieldName)); 
                    }
                    if (twoWayBound) { 
                        throw new HttpException(SR.GetString(SR.TwoWayBinding_requires_ID, _controlType.Name, fieldName));
                    }
                }
 
                Debug.Assert(ControlType != null, "ControlType should not be null if we're adding a property entry");
                // We only support databindings on objects that have an event named "DataBinding" 
                if (!flags[controlTypeIsControl]) { 
                    if (ControlType.GetEvent("DataBinding") == null) {
                        throw new InvalidOperationException(SR.GetString(SR.ControlBuilder_DatabindingRequiresEvent, _controlType.FullName)); 
                    }
                }
            }
            else { 
                // If we don't have an expression builder yet, go get it
                if (expressionBuilder == null) { 
                    expressionBuilder = ExpressionBuilder.GetExpressionBuilder(expressionPrefix, VirtualPath, host); 
                }
            } 

            Debug.Assert(!(String.IsNullOrEmpty(expressionPrefix) ^ (expressionBuilder == null)), "expressionBuilder should be non-null iff expressionPrefix is non-empty");

            // Set up a BoundPropertyEntry since we know this is an expression 
            BoundPropertyEntry entry = new BoundPropertyEntry();
 
            entry.Filter = filter; 
            entry.Expression = expression;
            entry.ExpressionBuilder = expressionBuilder; 
            entry.ExpressionPrefix = expressionPrefix;
            entry.Generated = generated;
            entry.FieldName = fieldName;
            entry.FormatString = formatString; 
            entry.ControlType = _controlType;
            entry.ControlID = controlID; 
            entry.TwoWayBound = twoWayBound; 
            entry.ParsedExpressionData = parsedExpressionData;
 
            FillUpBoundPropertyEntry(entry, name);

            // Check for duplicate bound property entries and throws if it finds one.
            // This is done here rather than on AddBoundProperty(BoundPropertyEntry entry) since 
            // that overload can be called by other control builders in two-way binding scenarios.
            // In that case it is valid to have duplicate bound property entries since they are on 
            // the BindableTemplateBuilder, not the control's ControlBuilder. 
            foreach (BoundPropertyEntry bpe in BoundPropertyEntriesInternal) {
                if (String.Equals(bpe.Name, entry.Name, StringComparison.OrdinalIgnoreCase) && 
                    String.Equals(bpe.Filter, entry.Filter, StringComparison.OrdinalIgnoreCase)) {
                    string fullPropertyName = entry.Name;
                    if (!String.IsNullOrEmpty(entry.Filter)) {
                        fullPropertyName = entry.Filter + ":" + fullPropertyName; 
                    }
                    throw new InvalidOperationException(SR.GetString(SR.ControlBuilder_CannotHaveMultipleBoundEntries, fullPropertyName, ControlType)); 
                } 
            }
 
            // Add these to the bound entries
            AddBoundProperty(entry);
        }
 
        private void AddBoundProperty(BoundPropertyEntry entry) {
            // Add these to the bound entries 
            AddEntry(BoundPropertyEntriesInternal, entry); 

            if (entry.TwoWayBound) { 
                // Remember that this builder has some two-way entries
                flags[hasTwoWayBoundProps] = true;
            }
        } 

        private void FillUpBoundPropertyEntry(BoundPropertyEntry entry, string name) { 
 
            // Grab a member info corresponding to the property
            string objectModelName; 

            MemberInfo memberInfo = PropertyMapper.GetMemberInfo(_controlType, name, out objectModelName);
            entry.Name = objectModelName;
 
            // If we got a memberInfo
            if (memberInfo != null) { 
 
                if (memberInfo is PropertyInfo) {
                    // If it's a property, make sure it is persistable 
                    PropertyInfo propInfo = ((PropertyInfo)memberInfo);

                    if (propInfo.GetSetMethod() == null) {
                        if (!SupportsAttributes) { 
                            throw new HttpException(SR.GetString(SR.Property_readonly, name));
                        } 
                        else { 
                            // If the property is readonly, fall back to using SetAttribute
                            if (entry.TwoWayBound) { 
                                entry.ReadOnlyProperty = true;
                            }
                            else {
                                entry.UseSetAttribute = true; 
                            }
                        } 
                    } 
                    else {
                        // The property is settable, so we can use it 
                        entry.PropertyInfo = propInfo;
                        entry.Type = propInfo.PropertyType;
                    }
 
                }
                else { 
                    // If it's a field, just grab the type 
                    Debug.Assert(memberInfo is FieldInfo);
                    entry.Type = ((FieldInfo)memberInfo).FieldType; 
                }
            }
                // If we didn't find a member, we need to use the IAttributeAccessor
            else { 
                if (!SupportsAttributes) {
                    throw new HttpException(SR.GetString( 
                        SR.Type_doesnt_have_property, _controlType.FullName, name)); 
                }
                else { 
                    if (entry.TwoWayBound) {
                        throw new InvalidOperationException(SR.GetString(SR.ControlBuilder_TwoWayBindingNonProperty, name, ControlType.Name));
                    }
                    entry.Name = name; 
                    entry.UseSetAttribute = true;
                } 
            } 

            // Make sure we have parsed expression data 
            if (entry.ParsedExpressionData == null) {
                entry.ParseExpression(new ExpressionBuilderContext(VirtualPath));
            }
 
            if (!Parser.IgnoreParseErrors && entry.ParsedExpressionData == null) {
                // Disallow empty expressions ( 
                if (Util.IsWhiteSpaceString(entry.Expression)) { 

                    throw new HttpException( 
                        SR.GetString(SR.Empty_expression));
                }
            }
        } 

 
        ///  
        /// 
        private void AddCollectionItem(ControlBuilder builder) { 
            // Just save the builder and filter and add it to the complex entries
            ComplexPropertyEntry entry = new ComplexPropertyEntry(true);

            entry.Builder = builder; 
            entry.Filter = String.Empty;
            AddEntry(ComplexPropertyEntriesInternal, entry); 
        } 

 
        /// 
        /// 
        private void AddComplexProperty(string filter, string name, ControlBuilder builder) {
 
            //
 
            /* 
            if (IgnoreControlProperty) {
                return; 
            }
            */

            Debug.Assert(!String.IsNullOrEmpty(name)); 
            Debug.Assert(builder != null);
 
            // Look for a MemberInfo 
            string objectModelName = String.Empty;
            MemberInfo memberInfo = PropertyMapper.GetMemberInfo(_controlType, name, out objectModelName); 

            // Initialize the entry
            ComplexPropertyEntry entry = new ComplexPropertyEntry();
 
            entry.Builder = builder;
            entry.Filter = filter; 
            entry.Name = objectModelName; 

            Type memberType = null; 

            if (memberInfo != null) {
                if (memberInfo is PropertyInfo) {
                    PropertyInfo propInfo = ((PropertyInfo)memberInfo); 

                    entry.PropertyInfo = propInfo; 
                    if (propInfo.GetSetMethod() == null) { 
                        entry.ReadOnly = true;
                    } 

                    // Check if the property is themeable and persistable
                    ValidatePersistable(propInfo, false, false, false, filter);
                    memberType = propInfo.PropertyType; 
                }
                else { 
                    Debug.Assert(memberInfo is FieldInfo); 
                    memberType = ((FieldInfo)memberInfo).FieldType;
                } 

                entry.Type = memberType;
            }
            else { 
                throw new HttpException(SR.GetString(SR.Type_doesnt_have_property, _controlType.FullName, name));
            } 
 
            // Add the entry to the complex entries
            AddEntry(ComplexPropertyEntriesInternal, entry); 
        }

        /// 
        /// 
        /// 
        private void AddEntry(ArrayList entries, PropertyEntry entry) { 
            // Only allow setting the ID property of a control using a simple property (e.g. ID="Button1"). 
            // This restricts the user from using databinding, expressions, implicit expressions,
            // or inner string properties to set the ID. 
            if (String.Equals(entry.Name, "ID", StringComparison.OrdinalIgnoreCase) &&
                flags[controlTypeIsControl] &&
                !(entry is SimplePropertyEntry)) {
                throw new HttpException(SR.GetString(SR.ControlBuilder_IDMustUseAttribute)); 
            }
 
            // Remember the item index to perform a stable sort. 
            entry.Index = entries.Count;
 
            // We used to sort the entries here via an insertion-type sort
            // But it's faster just to sort before we use the entries.
            entries.Add(entry);
        } 

        ///  
        // 
        //// 
        private void AddProperty(string filter, string name, string value, bool mainDirectiveMode) { 
            Debug.Assert(!String.IsNullOrEmpty(name));

            if (IgnoreControlProperty) {
                return; 
            }
 
            string objectModelName = String.Empty; 
            MemberInfo memberInfo = null;
 
            // This _controlType can be null if we're using a StringPropertyBuilder that has designer expandos
            if (_controlType != null) {
                if (String.Equals(name, BaseTemplateCodeDomTreeGenerator.skinIDPropertyName, StringComparison.OrdinalIgnoreCase) &&
                    flags[controlTypeIsControl]) { 

                    // Make sure there isn't filter for skinID property. 
                    if (!String.IsNullOrEmpty(filter)) { 
                        throw new InvalidOperationException(SR.GetString(SR.Illegal_Device, BaseTemplateCodeDomTreeGenerator.skinIDPropertyName));
                    } 

                    SkinID = value;
                    return;
                } 

                memberInfo = PropertyMapper.GetMemberInfo(_controlType, name, out objectModelName); 
            } 

            if (memberInfo != null) { 

                // Found a property on the object, so start building a simple property setter
                SimplePropertyEntry entry = new SimplePropertyEntry();
 
                entry.Filter = filter;
                entry.Name = objectModelName; 
                entry.PersistedValue = value; 

                Type memberType = null; 

                if (memberInfo is PropertyInfo) {
                    PropertyInfo propInfo = ((PropertyInfo)memberInfo);
 
                    entry.PropertyInfo = propInfo;
 
                    // If the property is read-only 
                    if (propInfo.GetSetMethod() == null) {
                        if (!SupportsAttributes) { 
                            // If it doesn't support attributes, throw an exception
                            throw new HttpException(SR.GetString(SR.Property_readonly, name));
                        }
                        else { 
                            // Otherwise, use the attribute accessor
                            entry.UseSetAttribute = true; 
 
                            // Use the original casing of the name from the parsed data
                            entry.Name = name; 
                        }
                    }

                    ValidatePersistable(propInfo, entry.UseSetAttribute, mainDirectiveMode, true, filter); 
                    memberType = propInfo.PropertyType;
                } 
                else { 
                    Debug.Assert(memberInfo is FieldInfo);
                    memberType = ((FieldInfo)memberInfo).FieldType; 
                }

                entry.Type = memberType;
                if (entry.UseSetAttribute) { 
                    entry.Value = value;
                } 
                else { 
                    // Get the actual value for the property and store it in the entry
                    object objectValue = PropertyConverter.ObjectFromString(memberType, memberInfo, value); 

                    DesignTimePageThemeParser themeParser = Parser as DesignTimePageThemeParser;
                    if (themeParser != null) {
                        object[] attrs = memberInfo.GetCustomAttributes(typeof(UrlPropertyAttribute), true); 
                        if (attrs.Length > 0) {
                            string url = objectValue.ToString(); 
                            // Do not combine the url if it's apprelative, let controls resolve the url. 
                            if (UrlPath.IsRelativeUrl(url) && !UrlPath.IsAppRelativePath(url)) {
                                objectValue = themeParser.ThemePhysicalPath + url; 
                            }
                        }
                    }
 
                    entry.Value = objectValue;
 
                    // 

                    if (memberType.IsEnum) { 
                        if (objectValue == null) {
                            throw new HttpException(SR.GetString(SR.Invalid_enum_value, value, name, entry.Type.FullName));
                        }
 
                        entry.PersistedValue = Enum.Format(memberType, objectValue, "G");
                    } 
                    else if (memberType == typeof(Boolean)) { 
                        //
                        if (objectValue == null) { 
                            entry.Value = true;
                        }
                    }
                } 

                AddEntry(SimplePropertyEntriesInternal, entry); 
            } 
            else {
                bool foundEvent = false; 

                // Check if the property is actually an event handler
                if (StringUtil.StringStartsWithIgnoreCase(name, "on")) {
                    string eventName = name.Substring(2); 
                    EventDescriptor eventDesc = EventDescriptors.Find(eventName, true);
 
                    if (eventDesc != null) { 
                        if (InPageTheme) {
                            throw new HttpException(SR.GetString(SR.Property_theme_disabled, eventName, ControlType.FullName)); 
                        }

                        if (value != null)
                            value = value.Trim(); 

                        if (String.IsNullOrEmpty(value)) { 
                            throw new HttpException(SR.GetString(SR.Event_handler_cant_be_empty, name)); 
                        }
 
                        if (filter.Length > 0) {
                            throw new HttpException(SR.GetString(SR.Events_cant_be_filtered, filter, name));
                        }
 
                        foundEvent = true;
 
                        // First, give the PageParserFilter a chance to handle the event hookup 
                        if (!Parser.PageParserFilterProcessedEventHookupAttribute(ID, eventDesc.Name, value)) {
                            // Make sure event handlers are allowed. In no-compile pages, they aren't. ( 
                            Parser.OnFoundEventHandler(name);

                            EventEntry entry = new EventEntry();
 
                            entry.Name = eventDesc.Name;
                            entry.HandlerType = eventDesc.EventType; 
                            entry.HandlerMethodName = value; 
                            EventEntriesInternal.Add(entry);
                        } 
                    }
                }

                // If we didn't find an eventhandler, we need to use the IAttributeAccessor 
                if (!foundEvent) {
                    // Allow the designer filter expandos for simple attributes 
                    if (!SupportsAttributes && (filter != DesignerFilter)) { 
                        if (_controlType != null) {
                            throw new HttpException(SR.GetString(SR.Type_doesnt_have_property, _controlType.FullName, name)); 
                        }
                        else {
                            throw new HttpException(SR.GetString(SR.Property_doesnt_have_property, TagName, name));
                        } 
                    }
 
                    SimplePropertyEntry entry = new SimplePropertyEntry(); 

                    entry.Filter = filter; 
                    entry.Name = name;
                    entry.PersistedValue = value;
                    entry.UseSetAttribute = true;
                    entry.Value = value; 
                    AddEntry(SimplePropertyEntriesInternal, entry);
                } 
            } 
        }
 

        /// 
        /// 
        private void AddTemplateProperty(string filter, string name, TemplateBuilder builder) { 

            /* Do not ignore template properties since we do want to generate IDs for controls defined 
               inside SingleInstanceTemplates. 

 

*/

            Debug.Assert(!String.IsNullOrEmpty(name)); 
            Debug.Assert(builder != null);
 
            // Look for a MemberInfo 
            string objectModelName = String.Empty;
            MemberInfo memberInfo = PropertyMapper.GetMemberInfo(_controlType, name, out objectModelName); 

            // Setup a template entry
            bool bindableTemplate = builder is BindableTemplateBuilder;
            TemplatePropertyEntry entry = new TemplatePropertyEntry(bindableTemplate); 

            entry.Builder = builder; 
            entry.Filter = filter; 
            entry.Name = objectModelName;
 
            Type memberType = null;

            if (memberInfo != null) {
                if (memberInfo is PropertyInfo) { 

                    PropertyInfo propInfo = ((PropertyInfo)memberInfo); 
 
                    entry.PropertyInfo = propInfo;
 
                    ValidatePersistable(propInfo, false, false, false, filter);

                    // Check the attribute on the property to see if it has a ContainerType
                    TemplateContainerAttribute templateAttrib = (TemplateContainerAttribute)Attribute.GetCustomAttribute(propInfo, typeof(TemplateContainerAttribute), false); 

                    if (templateAttrib != null) { 
                        if (!typeof(INamingContainer).IsAssignableFrom(templateAttrib.ContainerType)) { 
                            throw new HttpException(SR.GetString(SR.Invalid_template_container, name, templateAttrib.ContainerType.FullName));
                        } 

                        // If it had one, make sure the builder knows what type it is
                        builder.SetControlType(templateAttrib.ContainerType);
                    } 

                    entry.Type = propInfo.PropertyType; 
                } 
                else {
                    Debug.Assert(memberInfo is FieldInfo); 
                    memberType = ((FieldInfo)memberInfo).FieldType;
                }

                entry.Type = memberType; 
            }
            else { 
                throw new HttpException(SR.GetString(SR.Type_doesnt_have_property, _controlType.FullName, name)); 
            }
 
            // Add it to the template entries
            AddEntry(TemplatePropertyEntriesInternal, entry);
        }
 
        /// 
        /// 
        ///  
        internal void AddSubBuilder(object o) {
            SubBuilders.Add(o); 
        }

        internal bool HasTwoWayBoundProperties {
            get { 
                return flags[hasTwoWayBoundProps];
            } 
        } 

 
        /// 
        ///
        /// 
        public virtual bool AllowWhitespaceLiterals() { 
            return true;
        } 
 

        ///  
        ///
        /// 
        public virtual void AppendLiteralString(string s) {
            // Ignore null strings 
            if (s == null) {
                return; 
            } 

            // If we are not building a control, or if our children define 
            // properties, we should not get literal strings.  Ignore whitespace
            // ones, and fail for others
            if (FIsNonParserAccessor || FChildrenAsProperties) {
                // If there is a default property, delegate to its builder 
                if (DefaultPropertyBuilder != null) {
                    DefaultPropertyBuilder.AppendLiteralString(s); 
                    return; 
                }
 
                s = s.Trim();
                if (FChildrenAsProperties) {
                    // Throw a better error message if the content start with the '<' char.
                    if (s.StartsWith("<", StringComparison.OrdinalIgnoreCase)) { 
                        throw new HttpException(SR.GetString(SR.Literal_content_not_match_property, _controlType.FullName, s));
                    } 
                } 

                if (s.Length != 0) { 
                    throw new HttpException(SR.GetString(SR.Literal_content_not_allowed, _controlType.FullName, s));
                }

                return; 
            }
 
            // Ignore literals that are just whitespace if the control does not want them 
            if ((AllowWhitespaceLiterals() == false) && Util.IsWhiteSpaceString(s))
                return; 

            // A builder can specify its strings need to be html decoded
            if (HtmlDecodeLiterals()) {
                s = HttpUtility.HtmlDecode(s); 
            }
 
            // If the last builder is a DataBoundLiteralControlBuilder, add the string 
            // to it instead of to our list of sub-builders
            object lastBuilder = GetLastBuilder(); 
            DataBoundLiteralControlBuilder dataBoundBuilder = lastBuilder as DataBoundLiteralControlBuilder;

            if (dataBoundBuilder != null) {
                Debug.Assert(!InDesigner, "!InDesigner"); 
                dataBoundBuilder.AddLiteralString(s);
            } 
            else { 
                AddSubBuilder(s);
            } 
        }


        ///  
        ///
        ///  
        public virtual void AppendSubBuilder(ControlBuilder subBuilder) { 
            // Tell the sub builder that it's about to be appended to its parent
            subBuilder.OnAppendToParentBuilder(this); 
            if (FChildrenAsProperties) {
                // Don't allow code blocks when properties are expected (ASURT 97838)
                if (subBuilder is CodeBlockBuilder) {
                    throw new HttpException(SR.GetString(SR.Code_not_supported_on_not_controls)); 
                }
 
                // If there is a default property, delegate to its builder 
                if (DefaultPropertyBuilder != null) {
                    DefaultPropertyBuilder.AppendSubBuilder(subBuilder); 
                    return;
                }

                // The tagname is the property name 
                string propName = subBuilder.TagName;
 
                if (subBuilder is TemplateBuilder) { 
                    TemplateBuilder tplBuilder = (TemplateBuilder)subBuilder;
 
                    AddTemplateProperty(tplBuilder.Filter, propName, tplBuilder);
                }
                else if (subBuilder is CollectionBuilder) {
                    // If there are items in the collection, add them 
                    if ((subBuilder.SubBuilders != null) && (subBuilder.SubBuilders.Count > 0)) {
                        IEnumerator subBuilders = subBuilder.SubBuilders.GetEnumerator(); 
 
                        while (subBuilders.MoveNext()) {
                            ControlBuilder builder = (ControlBuilder)subBuilders.Current; 

                            subBuilder.AddCollectionItem(builder);
                        }
 
                        subBuilder.SubBuilders.Clear();
                        AddComplexProperty(subBuilder.Filter, propName, subBuilder); 
                    } 
                }
                else if (subBuilder is StringPropertyBuilder) { 
                    // Trim this so whitespace doesn't matter inside a tag?
                    string text = ((StringPropertyBuilder)subBuilder).Text.Trim();

                    if (!String.IsNullOrEmpty(text)) { 
                        // Make sure we haven't set this property in the attributes already (special case for TextBox and similar things)
                        AddComplexProperty(subBuilder.Filter, propName, subBuilder); 
                    } 
                }
                else { 
                    AddComplexProperty(subBuilder.Filter, propName, subBuilder);
                }

                return; 
            }
 
            CodeBlockBuilder codeBlockBuilder = subBuilder as CodeBlockBuilder; 

            if (codeBlockBuilder != null) { 
                // Don't allow code blocks inside non-control tags (ASURT 76719)
                if (ControlType != null && !flags[controlTypeIsControl]) {
                    throw new HttpException(SR.GetString(SR.Code_not_supported_on_not_controls));
                } 

                // Is it a databinding expression?  <%# ... %> 
                if (codeBlockBuilder.BlockType == CodeBlockType.DataBinding) { 
                    // Bind statements are not allowed as DataBoundLiterals inside any template.
                    // Outside a template, they should be treated as calls to page code. 
                    Match match;

                    if ((match = bindExpressionRegex.Match(codeBlockBuilder.Content, 0)).Success) {
                        ControlBuilder currentBuilder = this; 

                        while (currentBuilder != null && !(currentBuilder is TemplateBuilder)) { 
                            currentBuilder = currentBuilder.ParentBuilder; 
                        }
 
                        if (currentBuilder != null && currentBuilder.ParentBuilder != null && currentBuilder is TemplateBuilder) {
                            throw new HttpException(SR.GetString(SR.DataBoundLiterals_cant_bind));
                        }
                    } 

                    if (InDesigner) { 
                        // In the designer, don't use the fancy multipart DataBoundLiteralControl, 
                        // which breaks a number of things (ASURT 82925,86738).  Instead, use the
                        // simpler DesignerDataBoundLiteralControl, and do standard databinding 
                        // on its Text property.
                        IDictionary attribs = new ParsedAttributeCollection();

                        attribs.Add("Text", "<%#" + codeBlockBuilder.Content + "%>"); 
                        subBuilder = CreateBuilderFromType(Parser, this, typeof(DesignerDataBoundLiteralControl),
                            null, null, attribs, codeBlockBuilder.Line, codeBlockBuilder.VirtualPathString); 
                    } 
                    else {
                        // Get the last builder, and 
                        object lastBuilder = GetLastBuilder();
                        DataBoundLiteralControlBuilder dataBoundBuilder = lastBuilder as DataBoundLiteralControlBuilder;

                        // If not, then we need to create one.  Otherwise, just append to the 
                        // existing one
                        bool fNewDataBoundLiteralControl = false; 
 
                        if (dataBoundBuilder == null) {
                            dataBoundBuilder = new DataBoundLiteralControlBuilder(); 
                            dataBoundBuilder.Init(Parser, this, typeof(DataBoundLiteralControl), null, null, null);
                            dataBoundBuilder.Line = codeBlockBuilder.Line;
                            dataBoundBuilder.VirtualPath = codeBlockBuilder.VirtualPath;
                            fNewDataBoundLiteralControl = true; 

                            // If the previous builder was a string, add it as the first 
                            // entry in the composite control. 
                            string s = lastBuilder as string;
 
                            if (s != null) {
                                SubBuilders.RemoveAt(SubBuilders.Count - 1);
                                dataBoundBuilder.AddLiteralString(s);
                            } 
                        }
 
                        dataBoundBuilder.AddDataBindingExpression(codeBlockBuilder); 
                        if (!fNewDataBoundLiteralControl)
                            return; 

                        subBuilder = dataBoundBuilder;
                    }
                } 
                else {
                    // Set a flag if there is at least one block of ASP code 
                    ParseTimeData.HasAspCode = true; 
                }
            } 

            if (FIsNonParserAccessor) {
                throw new HttpException(SR.GetString(SR.Children_not_supported_on_not_controls));
            } 

            AddSubBuilder(subBuilder); 
        } 

        ///  
        /// Builds all child ControlBuilders of this ControlBuilder.
        /// Only used in the no-compile scenario.
        /// 
        internal virtual void BuildChildren(object parentObj) { 
            // Create all the children
            if (_subBuilders != null) { 
                IEnumerator en = _subBuilders.GetEnumerator(); 

                for (int i = 0; en.MoveNext(); i++) { 
                    object childObj;
                    object cur = en.Current;

                    if (cur is string) { 
                        childObj = new LiteralControl((string)cur);
                    } 
                    else if (cur is CodeBlockBuilder) { 
                        //
 
                        continue;
                    }
                    else {
                        ControlBuilder controlBuilder = (ControlBuilder)cur; 

                        Debug.Assert(controlBuilder.ServiceProvider == null); 
                        controlBuilder.SetServiceProvider(ServiceProvider); 
                        try {
                            childObj = controlBuilder.BuildObject(flags[applyTheme]); 

                            // If it's a user control, call its InitializeAsUserControl
                            if (!InDesigner) {
                                UserControl uc = childObj as UserControl; 

                                if (uc != null) { 
                                    Control parent = parentObj as Control; 

                                    Debug.Assert(parent != null); 
                                    uc.InitializeAsUserControl(parent.Page);
                                }
                            }
                        } finally { 
                            controlBuilder.SetServiceProvider(null);
                        } 
                    } 

                    Debug.Assert(childObj != null); 
                    Debug.Assert(typeof(IParserAccessor).IsAssignableFrom(parentObj.GetType()));
                    ((IParserAccessor)parentObj).AddParsedSubObject(childObj);
                }
            } 
        }
 
 
        /// 
        /// This code is only used in the no-compile mode. 
        /// It is used at design-time and when the user calls Page.ParseControl.
        /// 
        public virtual object BuildObject() {
            return BuildObjectInternal(); 
        }
 
        // Helper which sets themebility (This will only ever be true in the designer) 
        internal object BuildObject(bool shouldApplyTheme) {
            if (flags[applyTheme] != shouldApplyTheme) 
                flags[applyTheme] = shouldApplyTheme;
            return BuildObject();
        }
 
        internal object BuildObjectInternal() {
            // Can't assertt these anymore since we've discarded this information by the time we call this method 
            // Debug.Assert(InDesigner || CompilationMode == CompilationMode.Never, "Expected to be in designer mode."); 
            // Since getting the ConstructorNeedsTagAttribute is very expensive, cache
            // the result in a flag 
            if (!flags[needsTagAttributeComputed]) {
                // If it has a ConstructorNeedsTagAttribute, it needs a tag name
                ConstructorNeedsTagAttribute cnta = (ConstructorNeedsTagAttribute)TypeDescriptor.GetAttributes(ControlType)[typeof(ConstructorNeedsTagAttribute)];
 
                if (cnta != null && cnta.NeedsTag) {
                    flags[needsTagAttribute] = true; 
                } 

                // Remember that we have cached it 
                flags[needsTagAttributeComputed] = true;
            }

            Object obj; 

            if (flags[needsTagAttribute]) { 
                // Create the object, using its ctor that takes the tag name 
                Object[] args = new Object[] { TagName };
 
                obj = HttpRuntime.CreatePublicInstance(_controlType, args);
            }
            else {
                // Create the object 
                obj = HttpRuntime.FastCreatePublicInstance(_controlType);
            } 
 
            if (flags[applyTheme]) obj = GetThemedObject(obj);
 
            InitObject(obj);
            return obj;
        }
 

        ///  
        /// Called when the parser is done with parsing for this ControlBuilder. 
        /// 
        public virtual void CloseControl() { 
        }

        internal static ParsedAttributeCollection ConvertDictionaryToParsedAttributeCollection(IDictionary attribs) {
            if (attribs is ParsedAttributeCollection) { 
                return (ParsedAttributeCollection)attribs;
            } 
 
            // Assert here so we know our own code is never passign in a plain IDictionary
            // System.Web.Mobile does this, so we don't assertt 
            // Debug.Assert(false);
            ParsedAttributeCollection newAttribs = new ParsedAttributeCollection();

            foreach (DictionaryEntry entry in attribs) { 
                newAttribs.AddFilteredAttribute(String.Empty, entry.Key.ToString(), entry.Value.ToString());
            } 
 
            return newAttribs;
        } 

        internal ControlBuilder CreateChildBuilder(string filter, string tagName, IDictionary attribs, TemplateParser parser, ControlBuilder parentBuilder, string id, int line, VirtualPath virtualPath, ref Type childType, bool defaultProperty) {
            ControlBuilder subBuilder;
 
            if (FChildrenAsProperties) {
                // If there is a default property, delegate to its builder 
                if (DefaultPropertyBuilder != null) { 
                    //
                    PropertyInfo pInfo = _controlType.GetProperty(tagName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.IgnoreCase); 

                    if (pInfo != null) {
                        subBuilder = GetChildPropertyBuilder(tagName, attribs, ref childType, parser, false);
 
                        // If items have already been added to the default builder, throw an exception
                        if (DefaultPropertyBuilder.SubBuilders.Count > 0) { 
                            ParseChildrenAttribute pca = null; 
                            object[] attrs = ControlType.GetCustomAttributes(typeof(ParseChildrenAttribute), /*inherit*/ true);
 
                            pca = (ParseChildrenAttribute)attrs[0];
                            Debug.Assert(pca != null);
                            throw new HttpException(SR.GetString(SR.Cant_use_default_items_and_filtered_collection, _controlType.FullName, pca.DefaultProperty));
                        } 

                        // Can't use the default property builder anymore since we have filtered collections 
                        ParseTimeData.DefaultPropertyBuilder = null; 
                    }
                    else { 
                        subBuilder = DefaultPropertyBuilder.CreateChildBuilder(filter, tagName, attribs, parser, parentBuilder, id, line, virtualPath, ref childType, false /*defaultProperty*/);
                    }
                }
                else { 
                    subBuilder = GetChildPropertyBuilder(tagName, attribs, ref childType, parser, defaultProperty);
                } 
            } 
            else {
                string fullTagName = Util.CreateFilteredName(filter, tagName); 

                childType = GetChildControlType(fullTagName, attribs);
                if (childType == null) {
                    return null; 
                }
 
                // We have to pass in the fullTagName since these will be actual registered controls 
                subBuilder = CreateBuilderFromType(parser, parentBuilder, childType, fullTagName,
                    id, attribs, line, VirtualPathString); 
            }

            if (subBuilder == null) {
                return null; 
            }
 
            subBuilder.Filter = filter; 
            subBuilder.SetParentBuilder((parentBuilder != null) ? parentBuilder : this);
            return subBuilder; 
        }


        ///  
        /// Create a ControlBuilder for a given tag
        ///  
        public static ControlBuilder CreateBuilderFromType(TemplateParser parser, ControlBuilder parentBuilder, Type type, string tagName, string id, IDictionary attribs, int line, string sourceFileName) { 
            ControlBuilder builder = CreateBuilderFromType(type);
 
            //

            builder.Line = line;
            builder.VirtualPath = System.Web.VirtualPath.CreateAllowNull(sourceFileName); 

            // Initialize the builder 
            builder.Init(parser, parentBuilder, type, tagName, id, attribs); 
            return builder;
        } 

#if !DONTUSEFACTORYGENERATOR
        // Cache instances of IWebObjectFactory for each control Type, which allow us
        // to instantiate the builders very efficiently, compared to calling 
        // GetCustomAttributes and Activator.CreateInstance on every call.
        private static FactoryGenerator s_controlBuilderFactoryGenerator; 
#endif // DONTUSEFACTORYGENERATOR 
        private static Hashtable s_controlBuilderFactoryCache;
 
        private static ControlBuilder CreateBuilderFromType(Type type) {
            // Create the factory generator on demand
            if (s_controlBuilderFactoryCache == null) {
#if !DONTUSEFACTORYGENERATOR 
                s_controlBuilderFactoryGenerator = new FactoryGenerator();
#endif // DONTUSEFACTORYGENERATOR 
 
                // Create the factory cache
                s_controlBuilderFactoryCache = Hashtable.Synchronized(new Hashtable()); 

                // Seed the cache with a few types that we don't want to expose as public (they
                // need to be public for FactoryGenerator to be used).
                s_controlBuilderFactoryCache[typeof(Content)] = new ContentBuilderInternalFactory(); 
                s_controlBuilderFactoryCache[typeof(ContentPlaceHolder)] = new ContentPlaceHolderBuilderFactory();
            } 
 
            // First,
            IWebObjectFactory factory = (IWebObjectFactory)s_controlBuilderFactoryCache[type]; 

            if (factory == null) {
                // Check whether the control's class exposes a custom builder type
                ControlBuilderAttribute cba = GetControlBuilderAttribute(type); 

                if (cba != null) { 
                    // Make sure the type has the correct base class (ASURT 123677) 
                    Util.CheckAssignableType(typeof(ControlBuilder), cba.BuilderType);
#if !DONTUSEFACTORYGENERATOR 
                    if (cba.BuilderType.IsPublic) {
                        // If the builder type is public, codegen a fast factory for it
                        factory = s_controlBuilderFactoryGenerator.CreateFactory(cba.BuilderType);
                    } 
                    else {
                        Debug.Assert(false, "The type " + cba.BuilderType.Name + " should be made public for better performance."); 
#endif // DONTUSEFACTORYGENERATOR 

                        // It's not public, so we must stick with slower reflection 
                        factory = new ReflectionBasedControlBuilderFactory(cba.BuilderType);
#if !DONTUSEFACTORYGENERATOR
                    }
#endif // DONTUSEFACTORYGENERATOR 
                }
                else { 
                    // use a factory that creates generic builders (i.e. ControlBuilder's) 
                    factory = s_defaultControlBuilderFactory;
                } 

                // Cache the factory
                s_controlBuilderFactoryCache[type] = factory;
            } 

            return (ControlBuilder) factory.CreateInstance(); 
        } 

        private static ControlBuilderAttribute GetControlBuilderAttribute(Type controlType) { 
            // Check whether the control's class exposes a custom builder type
            ControlBuilderAttribute cba = null;
            object[] attrs = controlType.GetCustomAttributes(typeof(ControlBuilderAttribute), /*inherit*/ true);
 
            if ((attrs != null) && (attrs.Length > 0)) {
                Debug.Assert(attrs[0] is ControlBuilderAttribute); 
                cba = (ControlBuilderAttribute)attrs[0]; 
            }
 
            return cba;
        }

        private ControlBuilder GetChildPropertyBuilder(string tagName, IDictionary attribs, ref Type childType, TemplateParser templateParser, bool defaultProperty) { 
            Debug.Assert(FChildrenAsProperties, "ChildrenAsProperties");
 
            // Parse the device filter if any 
            // The child is supposed to be a property, so look for it
            PropertyInfo pInfo = _controlType.GetProperty(tagName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.IgnoreCase); 

            if (pInfo == null) {
                throw new HttpException(SR.GetString(SR.Type_doesnt_have_property, _controlType.FullName, tagName));
            } 

            // Get its type 
            childType = pInfo.PropertyType; 

            ControlBuilder builder = null; 

            // If it's a collection, return the collection builder
            if (typeof(ICollection).IsAssignableFrom(childType)) {
                // Check whether the prop has an IgnoreUnknownContentAttribute 
                IgnoreUnknownContentAttribute attr = (IgnoreUnknownContentAttribute)Attribute.GetCustomAttribute(pInfo, typeof(IgnoreUnknownContentAttribute), true);
 
                builder = new CollectionBuilder(attr != null /*ignoreUnknownContent*/); 
            }
            else if (typeof(ITemplate).IsAssignableFrom(childType)) { 
                bool useBindableTemplate = false;
                bool allowMultipleInstances = true;
                object[] containerAttrs = pInfo.GetCustomAttributes(typeof(TemplateContainerAttribute), /*inherits*/ false);
 
                if ((containerAttrs != null) && (containerAttrs.Length > 0)) {
                    Debug.Assert(containerAttrs[0] is TemplateContainerAttribute); 
                    useBindableTemplate = (((TemplateContainerAttribute)containerAttrs[0]).BindingDirection == BindingDirection.TwoWay); 
                }
 
                object[] instanceAttrs = pInfo.GetCustomAttributes(typeof(TemplateInstanceAttribute), /*inherits*/ false);

                if ((instanceAttrs != null) && (instanceAttrs.Length > 0)) {
                    Debug.Assert(instanceAttrs[0] is TemplateInstanceAttribute); 
                    allowMultipleInstances = (((TemplateInstanceAttribute)instanceAttrs[0]).Instances == TemplateInstance.Multiple);
                } 
 
                if (useBindableTemplate) {  // If it's a bindable template, return the bindable template builder
                    builder = new BindableTemplateBuilder(); 
                }
                else {  // If it's a template, return the template builder
                    builder = new TemplateBuilder();
                } 

                if (builder is TemplateBuilder) { 
                    ((TemplateBuilder)builder).AllowMultipleInstances = allowMultipleInstances; 
                    // If we're in the designer, set a reference to the designer host
                    // so we can get to a filter resolution service later 
                    if (InDesigner) {
                        ((TemplateBuilder)builder).SetDesignerHost(templateParser.DesignerHost);
                    }
                } 
            }
            else if (childType == typeof(string)) { 
                PersistenceModeAttribute persistenceAttr = (PersistenceModeAttribute)Attribute.GetCustomAttribute(pInfo, typeof(PersistenceModeAttribute), true); 

                if (((persistenceAttr == null) || (persistenceAttr.Mode == PersistenceMode.Attribute)) && !defaultProperty) { 
                    // If the property is supposed to be declared as an attribute on a control tag, throw if it was declared as an inner property
                    // We don't throw if we are simply building the DefaultPropertyBuilder.
                    throw new HttpException(SR.GetString(SR.ControlBuilder_CannotHaveComplexString, _controlType.FullName, tagName));
                } 
                builder = new StringPropertyBuilder();
            } 
 
            if (builder != null) {
                builder.Line = Line; 
                builder.VirtualPath = VirtualPath;

                // Initialize the builder
                builder.Init(Parser, (ControlBuilder)this, null, tagName, null, attribs); 
                return builder;
            } 
 
            // Otherwise, simply return the builder for the property
            builder = CreateBuilderFromType(Parser, this, childType, tagName, null, 
                attribs, Line, VirtualPathString);
            return builder;
        }
 

        ///  
        /// When overridden, returns the control type of any parsed child controls 
        /// 
        public virtual Type GetChildControlType(string tagName, IDictionary attribs) { 
            return null;
        }

        ///  
        /// Convenience method for grabbing the set of property entries that we need to set
        /// on an instance of the object this controlbuilder builds. 
        ///  
        internal ICollection GetFilteredPropertyEntrySet(ICollection entries) {
            // If we encounter the default value, put it in the table if it doesn't already exist 
            // If we encounter the filter value, replace whatevers in the table.
            IDictionary filteredEntries = new HybridDictionary(true);
            IFilterResolutionService filterResolutionService = CurrentFilterResolutionService;
 
            if (filterResolutionService != null) {
                foreach (PropertyEntry entry in entries) { 
                    if (!filteredEntries.Contains(entry.Name)) { 
                        String filter = entry.Filter;
                        // empty filter always matches. 
                        if (String.IsNullOrEmpty(filter) || filterResolutionService.EvaluateFilter(filter)) {
                            filteredEntries[entry.Name] = entry;
                        }
                    } 
                }
            } 
            else { 
                // If there isn't a filter resolution service, just add anything from the default filter
                foreach (PropertyEntry entry in entries) { 
                    if (String.IsNullOrEmpty(entry.Filter)) {
                        filteredEntries[entry.Name] = entry;
                    }
                } 
            }
 
            return filteredEntries.Values; 
        }
 
        // Check if any of the entries have a filter
        private bool HasFilteredEntries(ICollection entries) {
            foreach (PropertyEntry entry in entries) {
                if (entry.Filter.Length > 0) 
                    return true;
            } 
 
            // None of the entries are filtered
            return false; 
        }

        /// 
        /// Return the last sub builder added to this builder 
        /// 
        internal object GetLastBuilder() { 
            if (SubBuilders.Count == 0) { 
                return null;
            } 

            return SubBuilders[SubBuilders.Count - 1];
        }
 

        public ObjectPersistData GetObjectPersistData() { 
            return new ObjectPersistData(this, Parser.RootBuilder.BuiltObjects); 
        }
 

        /// 
        /// Does this control have a body.  e.g.  doesn't.
        ///  
        public virtual bool HasBody() {
            return true; 
        } 

 
        public virtual bool HtmlDecodeLiterals() {
            return false;
        }
 

        ///  
        /// @param parser The instance of the parser that is controlling us. 
        /// @param tagName The name of the tag to be built.  This is necessary
        ///      to allow a builder to support multiple tag types. 
        /// @param attribs IDictionary which holds all the attributes of
        ///      the tag.  It is immutable.
        /// @param type Type of the control that this builder will create.
        ///  
        public virtual void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type, string tagName, string id, IDictionary attribs) {
#if DEBUG 
            Debug.Assert(!_initCalled, "ControlBuilder.Init() should never be called more than once on the same ControlBuilder."); 
            _initCalled = true;
#endif 

            ParseTimeData.Parser = parser;
            ParseTimeData.ParentBuilder = parentBuilder;
            if (parser != null) { 
                ParseTimeData.IgnoreControlProperties = parser.IgnoreControlProperties;
            } 
 
            _tagName = tagName;
            if (type != null) { 
                _controlType = type;
                flags[controlTypeIsControl] = typeof(Control).IsAssignableFrom(_controlType);

                ID = id; 

                // Try to get a ParseChildrenAttribute from the object 
                ParseChildrenAttribute pca = GetParseChildrenAttribute(type); 

                // Is this a builder for an object that implements IParserAccessor? 
                if (!typeof(IParserAccessor).IsAssignableFrom(type)) {
                    ParseTimeData.IsNonParserAccessor = true;

                    // Non controls never have children 
                    ParseTimeData.ChildrenAsProperties = true;
                } 
                else { 
                    // Check if the nested tags define properties, as opposed to children
                    if (pca != null) { 
                        ParseTimeData.ChildrenAsProperties = pca.ChildrenAsProperties;
                    }
                }
 
                if (FChildrenAsProperties) {
                    // Check if there is a default property 
                    if (pca != null && pca.DefaultProperty.Length != 0) { 
                        Type subType = null;
 
                        // Create a builder for the default prop
                        // Default property is always the default filter
                        ParseTimeData.DefaultPropertyBuilder = CreateChildBuilder(String.Empty, pca.DefaultProperty, null/*attribs*/, parser, null, null /*id*/, Line, VirtualPath, ref subType, true /*defaultProperty*/);
                        Debug.Assert(DefaultPropertyBuilder != null, pca.DefaultProperty); 
                    }
                } 
 
                // Check if the object is an HtmlControl
                ParseTimeData.IsHtmlControl = typeof(HtmlControl).IsAssignableFrom(_controlType); 

                // Check if the object supports attributes
                ParseTimeData.SupportsAttributes = typeof(IAttributeAccessor).IsAssignableFrom(_controlType);
            } 
            else {
                flags[controlTypeIsControl] = false; 
            } 

            // Process the attributes, if any 
            if (attribs != null) {
                // This could be called by anyone, so if it's not the parser that's calling us
                // we have to copy all the attribs values over to a ParsedAttributeCollection
                // in the default filter 
                PreprocessAttributes(ConvertDictionaryToParsedAttributeCollection(attribs));
            } 
 
            // Check if the same control with identical skinID is already defined as a control skin.
            // If so, fails now instead of infinite recursion during runtime or designtime rendering. 
            //
            if (InPageTheme) {
                ControlBuilder builder = ((PageThemeParser)parser).CurrentSkinBuilder;
                if (builder != null && 
                    builder.ControlType == ControlType &&
                    String.Equals(builder.SkinID, SkinID, StringComparison.OrdinalIgnoreCase)) { 
                        throw new InvalidOperationException(SR.GetString(SR.Cannot_set_recursive_skin, builder.ControlType.Name)); 
                }
            } 
        }

        // Cache the custom ParseChildrenAttribute for each type to avoid having to call
        // GetCustomAttributes any more than necessary (it's extremely slow) 
        private static ParseChildrenAttribute s_markerParseChildrenAttribute = new ParseChildrenAttribute();
 
        private static Hashtable s_parseChildrenAttributeCache = new Hashtable(); 

        private static ParseChildrenAttribute GetParseChildrenAttribute(Type controlType) { 
            // First, see if we have it cached for this type
            ParseChildrenAttribute pca = (ParseChildrenAttribute)s_parseChildrenAttributeCache[controlType];

            if (pca == null) { 
                // Try to get a ParseChildrenAttribute from the type
                object[] attrs = controlType.GetCustomAttributes(typeof(ParseChildrenAttribute), /*inherit*/ true); 
 
                if ((attrs != null) && (attrs.Length > 0)) {
                    Debug.Assert(attrs[0] is ParseChildrenAttribute); 
                    pca = (ParseChildrenAttribute)attrs[0];
                }

                // If it doesn't have one, use a default as a marker 
                if (pca == null)
                    pca = s_markerParseChildrenAttribute; 
 
                // Cache the ParseChildrenAttribute
                lock (s_parseChildrenAttributeCache.SyncRoot) { 
                    s_parseChildrenAttributeCache[controlType] = pca;
                }
            }
 
            // If it's the marker one, just return null
            if (pca == s_markerParseChildrenAttribute) 
                return null; 

            return pca; 
        }

        private void DoInitObjectOptimizations(object obj) {
            // Cache whether it's an ICollection, since IsAssignableFrom is expensive 
            flags[isICollection] = typeof(ICollection).IsAssignableFrom(ControlType);
 
            // Cache whether it's an IParserAccessor, since IsAssignableFrom is expensive 
            flags[isIParserAccessor] = typeof(IParserAccessor).IsAssignableFrom(obj.GetType());
            if (_simplePropertyEntries != null) { 
                flags[hasFilteredSimpleProps] = HasFilteredEntries(_simplePropertyEntries);
            }

            if (_complexPropertyEntries != null) { 
                flags[hasFilteredComplexProps] = HasFilteredEntries(_complexPropertyEntries);
            } 
 
            if (_templatePropertyEntries != null) {
                flags[hasFilteredTemplateProps] = HasFilteredEntries(_templatePropertyEntries); 
            }

            if (_boundPropertyEntries != null) {
                flags[hasFilteredBoundProps] = HasFilteredEntries(_boundPropertyEntries); 
            }
        } 
 
        internal virtual object GetThemedObject(object obj) {
            Control control = obj as Control; 

            if (control == null) return obj;

            IThemeResolutionService themeService = ThemeResolutionService; 

            if (themeService != null) { 
                if (!String.IsNullOrEmpty(SkinID)) { 
                    control.SkinID = SkinID;
                } 

                // Apply the theme builders before we run the regular builders
                ThemeProvider themeProvider = themeService.GetStylesheetThemeProvider();
                SkinBuilder themeBuilder = null; 

                if (themeProvider != null) { 
                    themeBuilder = themeProvider.GetSkinBuilder(control); 
                    if (themeBuilder != null) {
                        try { 
                            themeBuilder.SetServiceProvider(ServiceProvider);
                            return themeBuilder.ApplyTheme();
                        } finally {
                            themeBuilder.SetServiceProvider(null); 
                        }
                    } 
                } 
            }
 
            return control;
        }

        ///  
        /// Sets all the properties of a built object corresponding to this ControlBuilder.
        /// This code is only used in the no-compile and designer modes 
        ///  
        internal virtual void InitObject(object obj) {
            // Can't assertt these anymore since we've discarded this information by the time we call this method 
            // Debug.Assert(InDesigner || CompilationMode == CompilationMode.Never, "Expected to be in designer mode.");
            // Make sure we initialize the property entries in the right order
            EnsureEntriesSorted();
 
            // Do some expensive one time pre-computations on demand
            if (!flags[doneInitObjectOptimizations]) { 
                DoInitObjectOptimizations(obj); 
                flags[doneInitObjectOptimizations] = true;
            } 

            Control control = obj as Control;
            if (control != null) {
                if (InDesigner) { 
                    control.SetDesignMode();
                } 
 
                if (SkinID != null) {
                    control.SkinID = SkinID; 
                }

                // Need to apply stylesheet on the controls in non-compiled pages.
                if (!InDesigner && TemplateControl != null) { 
                    control.ApplyStyleSheetSkin(TemplateControl.Page);
                } 
            } 

            InitSimpleProperties(obj); 
            if (flags[isICollection]) {
                InitCollectionsComplexProperties(obj);
            }
            else { 
                InitComplexProperties(obj);
            } 
 
            if (InDesigner) {
                if (control != null) { 
                    if (Parser.DesignTimeDataBindHandler != null) {
                        control.DataBinding += Parser.DesignTimeDataBindHandler;
                    }
 
                    // Set a reference to the control builder that created this object
                    control.SetControlBuilder(this); 
                } 

                Parser.RootBuilder.BuiltObjects[obj] = this; 
            }

            InitBoundProperties(obj);
 
            if (flags[isIParserAccessor]) {
                // Build the children 
                BuildChildren(obj); 
            }
 
            InitTemplateProperties(obj);

            if (control != null)
                BindFieldToControl(control); 

            // 
 

 
        }

        private void InitSimpleProperties(object obj) {
            // Don't do anything if there are no entries 
            if (_simplePropertyEntries == null)
                return; 
 
            // If there are no filters in the picture, use the entries as is
            ICollection entries; 

            if (flags[hasFilteredSimpleProps])
                entries = GetFilteredPropertyEntrySet(SimplePropertyEntries);
            else 
                entries = SimplePropertyEntries;
 
            // Now that we have the proper set, set all the entries 
            foreach (SimplePropertyEntry entry in entries) {
                SetSimpleProperty(entry, obj); 
            }
        }

        internal void SetSimpleProperty(SimplePropertyEntry entry, object obj) { 
            if (entry.UseSetAttribute) {
                ((IAttributeAccessor)obj).SetAttribute(entry.Name, entry.Value.ToString()); 
            } 
            else {
                try { 
                    PropertyMapper.SetMappedPropertyValue(obj, entry.Name, entry.Value);
                }
                catch (Exception e) {
                    throw new HttpException(SR.GetString(SR.Cannot_set_property, entry.PersistedValue, entry.Name), e); 
                }
            } 
        } 

        private void InitCollectionsComplexProperties(object obj) { 
            // Don't do anything if there are no entries
            if (_complexPropertyEntries == null)
                return;
 
            foreach (ComplexPropertyEntry entry in ComplexPropertyEntries) {
                try { 
                    ControlBuilder controlBuilder = ((ComplexPropertyEntry)entry).Builder; 
                    Debug.Assert(((ComplexPropertyEntry)entry).IsCollectionItem, "The entry should be a collection entry, instead it's a " + entry.GetType());
                    object objValue; 

                    Debug.Assert(controlBuilder.ServiceProvider == null);
                    controlBuilder.SetServiceProvider(ServiceProvider);
                    try { 
                        objValue = controlBuilder.BuildObject(flags[applyTheme]);
                    } finally { 
                        controlBuilder.SetServiceProvider(null); 
                    }
 
                    object[] parameters = new object[1];
                    parameters[0] = objValue;
                    MethodInfo methodInfo = ControlType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { objValue.GetType() }, null);
                    if (methodInfo == null) { 
                        throw new InvalidOperationException(SR.GetString(SR.ControlBuilder_CollectionHasNoAddMethod, TagName));
                    } 
                    Util.InvokeMethod(methodInfo, obj, parameters); 
                }
                catch (Exception ex) { 
                    throw new HttpException(SR.GetString(SR.Cannot_add_value_not_collection, TagName, ex.Message), ex);
                }
            }
        } 

        private void InitComplexProperties(object obj) { 
            // Don't do anything if there are no entries 
            if (_complexPropertyEntries == null)
                return; 

            // If there are no filters in the picture, use the entries as is
            ICollection entries;
 
            if (flags[hasFilteredComplexProps])
                entries = GetFilteredPropertyEntrySet(ComplexPropertyEntries); 
            else 
                entries = ComplexPropertyEntries;
 
            foreach (ComplexPropertyEntry entry in entries) {
                if (entry.ReadOnly) {
                    try {
                        object objectValue = FastPropertyAccessor.GetProperty(obj, entry.Name); 

                        entry.Builder.SetServiceProvider(ServiceProvider); 
                        try { 
                            // We must push the theme flag to child complex objects so they are init'd properly
 
                            // DevDiv Bug 59351
                            // Set applytheme only when necessary.
                            if (entry.Builder.flags[applyTheme] != flags[applyTheme]) {
                                entry.Builder.flags[applyTheme] = flags[applyTheme]; 
                            }
                            entry.Builder.InitObject(objectValue); 
                        } 
                        finally {
                            entry.Builder.SetServiceProvider(null); 
                        }
                    }
                    catch (Exception e) {
                        throw new HttpException(SR.GetString(SR.Cannot_init, entry.Name, e.Message), e); 
                    }
                } 
                else { 
                    try {
                        ControlBuilder controlBuilder = entry.Builder; 

                        Debug.Assert(controlBuilder.ServiceProvider == null);
                        object objectValue = null;
                        controlBuilder.SetServiceProvider(ServiceProvider); 
                        try {
                            objectValue = controlBuilder.BuildObject(flags[applyTheme]); 
                        } 
                        finally {
                            controlBuilder.SetServiceProvider(null); 
                        }

                        // Use the FastPropertyAccessor to assign the value
                        FastPropertyAccessor.SetProperty(obj, entry.Name, objectValue); 
                    }
                    catch (Exception e) { 
                        throw new HttpException(SR.GetString(SR.Cannot_set_property, TagName, entry.Name), e); 
                    }
                } 
            }
        }

        private void InitBoundProperties(object obj) { 
            // Don't do anything if there are no entries
            if (_boundPropertyEntries == null) 
                return; 

            DataBindingCollection dataBindings = null; 
            IAttributeAccessor attributeAccessor = null;

            // If there are no filters in the picture, use the entries as is
            ICollection entries; 

            if (flags[hasFilteredBoundProps]) 
                entries = GetFilteredPropertyEntrySet(BoundPropertyEntries); 
            else
                entries = BoundPropertyEntries; 

            foreach (BoundPropertyEntry entry in entries) {

                if (entry.TwoWayBound && this is BindableTemplateBuilder) { 
                    if (InDesigner) {
                        // Skip two-way entries for BindableTemplateBuilders in designer 
                        continue; 
                    }
                } 

                InitBoundProperty(obj, entry, ref dataBindings, ref attributeAccessor);
            }
        } 

        private void InitBoundProperty(object obj, BoundPropertyEntry entry, 
            ref DataBindingCollection dataBindings, ref IAttributeAccessor attributeAccessor) { 

            string expressionPrefix = entry.ExpressionPrefix == null ? String.Empty : entry.ExpressionPrefix.Trim(); 
            // If we're in the designer, add the bound properties to the collections
            if (InDesigner) {
                if (String.IsNullOrEmpty(expressionPrefix)) {
                    if (dataBindings == null && obj is IDataBindingsAccessor) { 
                        dataBindings = ((IDataBindingsAccessor)obj).DataBindings;
                    } 
 
                    dataBindings.Add(new DataBinding(entry.Name, entry.Type, entry.Expression.Trim()));
                } 
                else {
                    if (obj is IExpressionsAccessor) {
                        string expression = entry.Expression == null ? String.Empty : entry.Expression.Trim();
                        ((IExpressionsAccessor)obj).Expressions.Add(new ExpressionBinding(entry.Name, entry.Type, expressionPrefix, expression, entry.Generated, entry.ParsedExpressionData)); 
                    }
                } 
            } 
            // If we're in no-compile mode, set the values for expressions that support evaluate
            else { 
                if (!String.IsNullOrEmpty(expressionPrefix)) {
                    ExpressionBuilder eb = entry.ExpressionBuilder;
                    Debug.Assert(eb != null, "Did not expect null expression builder");
                    if (eb.SupportsEvaluate) { 
                        string name = entry.Name;
 
                        // DevDiv Bugs 160497: Create the expression context with whatever information we have. 
                        // We used to always use the TemplateControl one, but sometimes it's null, so we should
                        // fall back to the VirtualPath one if we can. 
                        ExpressionBuilderContext expressionContext;
                        if (TemplateControl != null) {
                            expressionContext = new ExpressionBuilderContext(TemplateControl);
                        } 
                        else {
                            expressionContext = new ExpressionBuilderContext(VirtualPath); 
                        } 
                        object value = eb.EvaluateExpression(obj, entry,
                            entry.ParsedExpressionData, expressionContext); 

                        if (entry.UseSetAttribute) {
                            if (attributeAccessor == null) {
                                Debug.Assert(obj is IAttributeAccessor); 
                                attributeAccessor = (IAttributeAccessor)obj;
                            } 
 
                            attributeAccessor.SetAttribute(name, value.ToString());
                        } 
                        else {
                            try {
                                PropertyMapper.SetMappedPropertyValue(obj, name, value);
                            } 
                            catch (Exception e) {
                                throw new HttpException(SR.GetString(SR.Cannot_set_property, entry.ExpressionPrefix + ":" + entry.Expression, name), e); 
                            } 
                        }
                    } 
                    else {
                        Debug.Fail("Got a ExpressionBuilder that does not support Evaluate in a non-compiled page");
                    }
                } 
                else {
                    // no-compile Bind property handling 
                    ((Control)obj).DataBinding += new EventHandler(DataBindingMethod); 
                }
            } 
        }

        private void DataBindingMethod(object sender, EventArgs e) {
            /*System.Web.UI.WebControls.DropDownList dataBindingExpressionBuilderTarget; 
            dataBindingExpressionBuilderTarget = ((System.Web.UI.WebControls.DropDownList)(sender));
            System.Web.UI.IDataItemContainer Container; 
            Container = ((System.Web.UI.IDataItemContainer)(dataBindingExpressionBuilderTarget.BindingContainer)); 
            if ((this.Page.GetDataItem() != null)) {
                dataBindingExpressionBuilderTarget.SelectedValue = System.Convert.ToString(this.Eval("FavVegetable")); 
            }*/

            bool isBindableTemplateBuilder = this is BindableTemplateBuilder;
            bool isTemplateBuilder = this is TemplateBuilder; 
            bool firstEntry = true;
            object evalValue; 
            Control containerControl = null; 

            ICollection entries; 

            // If there are no filters in the picture, use the entries as is
            if (!flags[hasFilteredBoundProps]) {
                entries = BoundPropertyEntries; 
            }
            else { 
                Debug.Assert(ServiceProvider == null); 
                Debug.Assert(TemplateControl != null, "TemplateControl should not be null in no-compile pages. We need it for the FilterResolutionService.");
 
                ServiceContainer container = new ServiceContainer();
                container.AddService(typeof(IFilterResolutionService), TemplateControl);

                try { 
                    SetServiceProvider(container);
                    entries = GetFilteredPropertyEntrySet(BoundPropertyEntries); 
                } 
                finally {
                    SetServiceProvider(null); 
                }
            }

            foreach (BoundPropertyEntry entry in entries) { 
                // Skip all one-way entries.  No-compile supported only on Bind statements.
                // Skip two-way entries if it's a BindableTemplateBuilder or the two way entry is read only 
                if ((entry.TwoWayBound && (isBindableTemplateBuilder || entry.ReadOnlyProperty)) 
                    || (!entry.TwoWayBound && isTemplateBuilder))
                    continue; 

                // We only care about databinding entries here
                if (!entry.IsDataBindingEntry)
                    continue; 

                Debug.Assert(!entry.UseSetAttribute, "Two-way binding is not supported on expandos - this should have been prevented in ControlBuilder"); 
 
                if (firstEntry) {
                    firstEntry = false; 

                    Debug.Assert(entry.ControlType.IsInstanceOfType(sender), "The DataBinding event sender was not of type " + entry.ControlType.Name);
                    if (_bindingContainerDescriptor == null) {
                        _bindingContainerDescriptor = TypeDescriptor.GetProperties(typeof(Control))["BindingContainer"]; 
                    }
                    object container = _bindingContainerDescriptor.GetValue(sender); 
                    containerControl = container as Control; 
                    if (containerControl.Page.GetDataItem() == null) {
                        break; // nothing to do if GetDataItem is null 
                    }
                }

                evalValue = containerControl.TemplateControl.Eval(entry.FieldName, entry.FormatString); 

                string objectModelName; 
                MemberInfo memberInfo = PropertyMapper.GetMemberInfo(entry.ControlType, entry.Name, out objectModelName); 
                // If destination is property:
                //     If destination type is string: 
                //         {{target}}.{{targetPropertyName}} = System.Convert.ToString( {{value}} );
                //     Else If destination type is reference type:
                //         {{target}}.{{targetPropertyName}} = ( {{destinationType}} ) {{value}};
                //     Else destination type is value type: 
                //         {{target}}.{{targetPropertyName}} = ( {{destinationType}} ) ({value});
                if (entry.Type.IsValueType && evalValue == null) { 
                    continue; 
                }
 
                object convertedValue = evalValue;
                if (entry.Type == typeof(string)) {
                    convertedValue = System.Convert.ToString(evalValue, CultureInfo.CurrentCulture);
                } 
                else if (evalValue != null && !entry.Type.IsAssignableFrom(evalValue.GetType())) {
                    convertedValue = PropertyConverter.ObjectFromString(entry.Type, memberInfo, System.Convert.ToString(evalValue, CultureInfo.CurrentCulture)); 
                } 

                PropertyMapper.SetMappedPropertyValue(sender, objectModelName, convertedValue); 
            }
        }

        private void InitTemplateProperties(object obj) { 
            // Don't do anything if there are no entries
            if (_templatePropertyEntries == null) 
                return; 

            object[] parameters = new object[1]; 

            // If there are no filters in the picture, use the entries as is
            ICollection entries;
 
            if (flags[hasFilteredTemplateProps])
                entries = GetFilteredPropertyEntrySet(TemplatePropertyEntries); 
            else 
                entries = TemplatePropertyEntries;
 
            foreach (TemplatePropertyEntry entry in entries) {
                try {
                    ControlBuilder controlBuilder = ((TemplatePropertyEntry)entry).Builder;
 
                    Debug.Assert(controlBuilder.ServiceProvider == null);
                    controlBuilder.SetServiceProvider(ServiceProvider); 
                    try { 
                        parameters[0] = controlBuilder.BuildObject(flags[applyTheme]);
                    } 
                    finally {
                        controlBuilder.SetServiceProvider(null);
                    }
 
                    MethodInfo methodInfo = entry.PropertyInfo.GetSetMethod();
 
                    Debug.Assert(methodInfo != null); 
                    Util.InvokeMethod(methodInfo, obj, parameters);
                } 
                catch (Exception e) {
                    throw new HttpException(SR.GetString(SR.Cannot_set_property, TagName, entry.Name), e);
                }
            } 
        }
 
        // If the page has a field which name matches the ID of this control, 
        // assign the control to the field.  This matches what we do for compiled
        // pages ( 
        private void BindFieldToControl(Control control) {

            // If we tried before and did not find a field, don't try again
            if (flags[triedFieldToControlBinding] && !flags[hasFieldToControlBinding]) 
                return;
 
            flags[triedFieldToControlBinding] = true; 

            TemplateControl templateControl = TemplateControl; 
            if (templateControl == null)
                return;

            Type templateControlType = TemplateControl.GetType(); 

            // This logic only needs to be checked once 
            if (!flags[hasFieldToControlBinding]) { 
                // This doesn't apply to designer scenarios.  It's only for no-compile pages.
                if (InDesigner) 
                    return;

                // Nothing to bind if the control doesn't have an ID
                if (control.ID == null) 
                    return;
 
                // If the TemplateControl is a built in class (Page or UserControl), 
                // there is no point in looking for fields.
                if (templateControlType.Assembly == typeof(HttpRuntime).Assembly) 
                    return;
            }

            // Try to find a field named after the ID in the TemplateControl 
            FieldInfo fieldInfo = templateControl.GetType().GetField(control.ID,
                BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 
 
            // If we couldn't find a field or it doesn't qualify, give up
            if (fieldInfo == null || fieldInfo.IsPrivate || !fieldInfo.FieldType.IsAssignableFrom(control.GetType())) { 
                return;
            }

            // Everything is in place, so set the field to the control 
            fieldInfo.SetValue(templateControl, control);
 
            // Remember that it was successful so we know we should try again next time 
            flags[hasFieldToControlBinding] = true;
        } 


        /// 
        /// Returns true is it needs SetTagInnerText() to be called. 
        /// 
        public virtual bool NeedsTagInnerText() { 
            return false; 
        }
 

        /// 
        /// This method is used to tell the builder that it's about to be appended to its parent.
        ///  
        public virtual void OnAppendToParentBuilder(ControlBuilder parentBuilder) {
            // If we have a default property, add it to ourselves 
            if (DefaultPropertyBuilder != null) { 
                ControlBuilder defaultPropBuilder = DefaultPropertyBuilder;
 
                // Need to make it null to avoid infinite recursion
                ParseTimeData.DefaultPropertyBuilder = null;
                AppendSubBuilder(defaultPropBuilder);
            } 

            if (!(this is BindableTemplateBuilder)) { 
                ControlBuilder currentBuilder = this; 

                while (currentBuilder != null && !(currentBuilder is BindableTemplateBuilder)) { 
                    currentBuilder = currentBuilder.ParentBuilder;
                }

                if (currentBuilder != null && currentBuilder is BindableTemplateBuilder) { 

                    // Add all the TwoWay BoundPropertyEntry's to the BindableTemplateBuilder 
                    foreach (BoundPropertyEntry entry in BoundPropertyEntries) { 
                        if (entry.TwoWayBound) {
                            ((BindableTemplateBuilder)currentBuilder).AddBoundProperty(entry); 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// Prepares this ControlBuilder and all of it's subbuilders for
        /// use in no-compile pages (minimizing the memory usage). 
        /// This makes the use of all parse-time properties invalid.
        /// 
        internal virtual void PrepareNoCompilePageSupport() {
            // Clear out all the flags and cached data from parse time 
            flags[parseComplete] = true;
            _parseTimeData = null; 
 
            // Remove any property entry lists that aren't being used
            if ((_eventEntries != null) && (_eventEntries.Count == 0)) { 
                _eventEntries = null;
            }

            if ((_simplePropertyEntries != null) && (_simplePropertyEntries.Count == 0)) { 
                _simplePropertyEntries = null;
            } 
 
            if (_complexPropertyEntries != null) {
                if (_complexPropertyEntries.Count == 0) { 
                    _complexPropertyEntries = null;
                }
                else {
                    foreach (BuilderPropertyEntry entry in _complexPropertyEntries) { 
                        if (entry.Builder != null)
                            entry.Builder.PrepareNoCompilePageSupport(); 
                    } 
                }
            } 

            if (_templatePropertyEntries != null) {
                if (_templatePropertyEntries.Count == 0) {
                    _templatePropertyEntries = null; 
                }
                else { 
                    foreach (BuilderPropertyEntry entry in _templatePropertyEntries) { 
                        if (entry.Builder != null)
                            entry.Builder.PrepareNoCompilePageSupport(); 
                    }
                }
            }
 
            if ((_boundPropertyEntries != null) && (_boundPropertyEntries.Count == 0)) {
                _boundPropertyEntries = null; 
            } 

            if (_subBuilders != null) { 
                if (_subBuilders.Count > 0) {
                    foreach (Object builderObj in _subBuilders) {
                        ControlBuilder builder = builderObj as ControlBuilder;
 
                        if (builder != null)
                            builder.PrepareNoCompilePageSupport(); 
                    } 
                }
                else { 
                    _subBuilders = null;
                }
            }
 
            // Sort the entry here to make sure we don't run into a race condition if we try to
            // do it later on demand ( 
            EnsureEntriesSorted(); 
        }
 
        /// 
        /// If the control has a Property which matches the name of the
        /// attribute, create an PropertyEntry for it, that will
        /// be used at BuildControl time. 
        /// 
        internal void PreprocessAttribute(string filter, string attribname, string attribvalue, bool mainDirectiveMode) { 
            Match match; 

            // Treat a null value as an empty string 
            if (attribvalue == null) {
                attribvalue = String.Empty;
            }
 
            if ((match = databindRegex.Match(attribvalue, 0)).Success) {
 
                // Don't process databinding expressions during updatable precomp, because we're only 
                // generating the base class, and only need the Type and ID of the controls (
                if (BuildManager.PrecompilingForUpdatableDeployment) 
                    return;

                string code = match.Groups["code"].Value;
 
                bool isParsedBindingStatement = false;
                bool isTwoWayBindingStatement = false; 
                if (!InDesigner) { 
                    if ((match = bindExpressionRegex.Match(code, 0)).Success) {
                        isParsedBindingStatement = true; 
                        isTwoWayBindingStatement = true;
                    }
                    // Treat it as a binding statement for skin files so the expression
                    // format will be checked first. 
                    else if ((CompilationMode == CompilationMode.Never || InPageTheme) &&
                        (match = evalExpressionRegex.Match(code, 0)).Success) { 
                        isParsedBindingStatement = true; 
                    }
                } 

                // Is it a two-way binding statement or eval in no-compile?
                if (isParsedBindingStatement) {
                    string paramString = match.Groups["params"].Value; 

                    if (!(match = bindParametersRegex.Match(paramString, 0)).Success) { 
                        throw new HttpException(SR.GetString(SR.BadlyFormattedBind)); 
                    }
 
                    string fieldName = match.Groups["fieldName"].Value;
                    string formatString = String.Empty;
                    Group formatStringGroup = match.Groups["formatString"];
 
                    if (formatStringGroup != null) {
                        formatString = formatStringGroup.Value; 
                    } 

                    if (formatString.Length > 0) { 
                        if (!(match = formatStringRegex.Match(formatString, 0)).Success) {
                            throw new HttpException(SR.GetString(SR.BadlyFormattedBind));
                        }
                    } 

                    // Pass the code expression to AddBoundProperty since the Eval expression needs to be compiled in skin files. 
                    // The bind expression needs to call without code 
                    if (InPageTheme && !isTwoWayBindingStatement) {
                        AddBoundProperty(filter, attribname, String.Empty, code, null /*expressionBuilder*/, null /*parsedExpressionData*/, String.Empty, String.Empty, false); 
                        return;
                    }

                    AddBoundProperty(filter, attribname, String.Empty, code, null /*expressionBuilder*/, null /*parsedExpressionData*/, fieldName, formatString, isTwoWayBindingStatement); 
                    return;
                } 
                else { 
                    // First, give the PageParserFilter a chance to handle the databinding
                    if (!Parser.PageParserFilterProcessedDataBindingAttribute(ID, attribname, code)) { 
                        // If it's a non compiled page and it's not a Bind or Eval statement, fail
                        Parser.EnsureCodeAllowed();

                        // Get the piece of code and add the property 
                        AddBoundProperty(filter, attribname, String.Empty, code, null /*expressionBuilder*/, null /*parsedExpressionData*/, String.Empty, String.Empty, false);
                    } 
                    return; 
                }
            } 
            else if ((match = expressionBuilderRegex.Match(attribvalue, 0)).Success) {
                if (InPageTheme) {
                    throw new HttpParseException(SR.GetString(SR.ControlBuilder_ExpressionsNotAllowedInThemes));
                } 

                // Don't process expression builders during updatable precomp, because we're only 
                // generating the base class, and only need the Type and ID of the controls ( 
                if (BuildManager.PrecompilingForUpdatableDeployment)
                    return; 

                string code = match.Groups["code"].Value.Trim();

                int indexOfColon = code.IndexOf(':'); 
                if (indexOfColon == -1) {
                    throw new HttpParseException(SR.GetString(SR.InvalidExpressionSyntax, attribvalue)); 
                } 

                string expressionPrefix = code.Substring(0, indexOfColon).Trim(); 
                string expressionCode = code.Substring(indexOfColon + 1).Trim();
                if (expressionPrefix.Length == 0) {
                    throw new HttpParseException(SR.GetString(SR.MissingExpressionPrefix, attribvalue));
                } 
                if (expressionCode.Length == 0) {
                    throw new HttpParseException(SR.GetString(SR.MissingExpressionValue, attribvalue)); 
                } 

                // If it's a non compiled page, fail if the expressiom builder has SupportsEvaluate==false 
                ExpressionBuilder expressionBuilder = null;
                if (CompilationMode == CompilationMode.Never) {
                    expressionBuilder = ExpressionBuilder.GetExpressionBuilder(expressionPrefix, Parser.CurrentVirtualPath);
                    if ((expressionBuilder != null) && !expressionBuilder.SupportsEvaluate) { 
                        throw new InvalidOperationException(SR.GetString(SR.Cannot_evaluate_expression, expressionPrefix + ":" + expressionCode));
                    } 
                } 

                AddBoundProperty(filter, attribname, expressionPrefix, expressionCode, expressionBuilder, null /*parsedExpressionData*/, String.Empty, String.Empty, false); 
                return;
            }

            AddProperty(filter, attribname, attribvalue, mainDirectiveMode); 
        }
 
        ///  
        /// Indicates whether this ControlBuilder should allow meta:localize and meta:resourcekey
        /// attributes on the tag. We only allow this for tags that represent controls and tags 
        /// that represent collection items.
        /// 
        private bool IsValidForImplicitLocalization() {
            if (flags[controlTypeIsControl]) { 
                // If this is a control, we can localize
                return true; 
            } 

            if (ParentBuilder == null) { 
                // We must have a parent builder
                return false;
            }
 
            // If we have a parent builder,
 
 
            if (ParentBuilder.DefaultPropertyBuilder != null) {
                return typeof(ICollection).IsAssignableFrom(ParentBuilder.DefaultPropertyBuilder.ControlType); 
            }
            else {
                return typeof(ICollection).IsAssignableFrom(ParentBuilder.ControlType);
            } 
        }
 
        ///  
        /// Process implicit resources if the control has a meta:resourcekey attribute
        ///  
        internal void ProcessImplicitResources(ParsedAttributeCollection attribs) {

            // Check if meta:localize="false" was specified.  Always do this since we need it at design-time
            string localize = (string)((IDictionary)attribs)["meta:localize"]; 
            if (localize != null) {
                // Depending on the control type, don't allow meta:localize (e.g. ITemplate case) ( 
                if (!IsValidForImplicitLocalization()) { 
                    throw new InvalidOperationException(SR.GetString(SR.meta_localize_notallowed, TagName));
                } 

                bool parseResult;
                if (!Boolean.TryParse(localize, out parseResult)) {
                    throw new HttpException(SR.GetString(SR.ControlBuilder_InvalidLocalizeValue, localize)); 
                }
                ParseTimeData.Localize = parseResult; 
            } 
            else {
                ParseTimeData.Localize = true; 
            }

            // Check whether a resource key was specified
            string keyPrefix = (string) ((IDictionary)attribs)["meta:resourcekey"]; 

            // Remove all meta attributes from the collection ( 
            attribs.ClearFilter("meta"); 

            if (keyPrefix == null) 
                return;

            // Depending on the control type, don't allow meta:reskey (e.g. ITemplate case) (
            if (!IsValidForImplicitLocalization()) { 
                throw new InvalidOperationException(SR.GetString(SR.meta_reskey_notallowed, TagName));
            } 
            Debug.Assert(_controlType != null, "If we get here then the tag type must be either an ICollection or a Control, so how can it be null?"); 

            // Restrict resource keys the same way as we restrict ID's ( 
            if (!System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(keyPrefix)) {
                throw new HttpException(SR.GetString(SR.Invalid_resourcekey, keyPrefix));
            }
 
            if (!ParseTimeData.Localize) {
                // If we have a key prefix (from meta:resourcekey) but we also have 
                // meta:localize=false, we throw. 
                throw new HttpException(SR.GetString(SR.meta_localize_error));
            } 

            ParseTimeData.ResourceKeyPrefix = keyPrefix;

            // Try to get the implicit resources for this specific Page 
            IImplicitResourceProvider implicitResourceProvider;
            if (Parser.FInDesigner && Parser.DesignerHost != null) { 
                implicitResourceProvider = (IImplicitResourceProvider)Parser.DesignerHost.GetService(typeof(IImplicitResourceProvider)); 
            }
            else { 
                implicitResourceProvider = Parser.GetImplicitResourceProvider();
            }

            // If the Page has resources, get the specific ones for this meta:resourcekey 
            ICollection tagResources = null;
            if (implicitResourceProvider != null) 
                tagResources = implicitResourceProvider.GetImplicitResourceKeys(keyPrefix); 

            if (tagResources != null) { 
                // Get the IDesignerHost in case we need it to find ExpressionBuilders
                IDesignerHost host = DesignerHost;

                // Note: this code expect that the "resources" expression builder be 
                // registered in config.  If the user removes it, they will get an error.
                ExpressionBuilder resourcesExpressionBuilder = ExpressionBuilder.GetExpressionBuilder("resources", Parser.CurrentVirtualPath, host); 
                bool usingStandardResources = typeof(ResourceExpressionBuilder) == resourcesExpressionBuilder.GetType(); 
                foreach (ImplicitResourceKey entry in tagResources) {
 
                    // Put together the complete resource key, as would appear in an explicit resource
                    string fullResourceKey = keyPrefix + "." + entry.Property;
                    if (entry.Filter.Length > 0)
                        fullResourceKey = entry.Filter + ':' + fullResourceKey; 

                    // Replace '.' with '-', since that's what AddBoundProperty expects 
                    string property = entry.Property.Replace('.', '-'); 

                    object parsedExpressionData = null; 
                    string expression;
                    if (usingStandardResources) {
                        // If we're using the standard System.Web.Compilation.ResourceExpressionBuilder
                        // we can optimized the parsed data. 
                        parsedExpressionData = ResourceExpressionBuilder.ParseExpression(fullResourceKey);
                        expression = String.Empty; 
                    } 
                    else {
                        expression = fullResourceKey; 
                    }

                    AddBoundProperty(entry.Filter, property, "resources",
                        expression, resourcesExpressionBuilder, parsedExpressionData, true, String.Empty, String.Empty, false); 
                }
            } 
        } 

        ///  
        /// Preprocess all the attributes at parse time, so that we'll be left
        /// with as little work as possible when we build the control.
        /// 
        private void PreprocessAttributes(ParsedAttributeCollection attribs) { 

            ProcessImplicitResources(attribs); 
 
            // Preprocess all the attributes
            foreach (FilteredAttributeDictionary filteredAttributes in attribs.GetFilteredAttributeDictionaries()) { 
                string filter = filteredAttributes.Filter;

                foreach (DictionaryEntry attribute in filteredAttributes) {
                    string name = attribute.Key.ToString(); 
                    string value = attribute.Value.ToString();
 
                    PreprocessAttribute(filter, name, value, false); 
                }
            } 
        }

        //
        public /* internal */ void SetServiceProvider(IServiceProvider serviceProvider) { 
            _serviceProvider = serviceProvider;
        } 
 
        internal void EnsureEntriesSorted() {
            // Always perform the sorting only once, even in derived classes, 
            // so as to avoid concurrency issues (DevDiv bugs 203787).
            if (!flags[entriesSorted]) {
                flags[entriesSorted] = true;
 
                SortEntries();
            } 
        } 

        internal virtual void SortEntries() { 
            // Don't sort the entries in a collection builder
            if (this is CollectionBuilder) {
                return;
            } 

            FilteredPropertyEntryComparer comparer = null; 
 
            ProcessAndSortPropertyEntries(_boundPropertyEntries, ref comparer);
            ProcessAndSortPropertyEntries(_complexPropertyEntries, ref comparer); 
            ProcessAndSortPropertyEntries(_simplePropertyEntries, ref comparer);
            ProcessAndSortPropertyEntries(_templatePropertyEntries, ref comparer);
        }
 

        internal void ProcessAndSortPropertyEntries(ArrayList propertyEntries, 
            ref FilteredPropertyEntryComparer comparer) { 

            if (propertyEntries != null && propertyEntries.Count > 1) { 
                HybridDictionary dictionary = new HybridDictionary(propertyEntries.Count, true);
                int index = 0;

                // Determine the order of the entry based on location of the first entry with the same name 
                foreach (PropertyEntry entry in propertyEntries) {
                    object o = dictionary[entry.Name]; 
                    if (o != null) { 
                        entry.Order = (int)o;
                    } 
                    else {
                        entry.Order = index;
                        dictionary.Add(entry.Name, index++);
                    } 
                }
 
                if (comparer == null) { 
                    comparer = new FilteredPropertyEntryComparer(CurrentFilterResolutionService);
                } 
                propertyEntries.Sort(comparer);
            }
        }
 
        /// 
        /// 
        ///  
        internal void SetControlType(Type controlType) {
            _controlType = controlType; 
            if (_controlType != null) {
                flags[controlTypeIsControl] = typeof(Control).IsAssignableFrom(_controlType);
            }
            else { 
                flags[controlTypeIsControl] = false;
            } 
        } 

        ///  
        /// Set the ControlBuilder that's the parent of this ControlBuilder
        /// 
        internal virtual void SetParentBuilder(ControlBuilder parentBuilder) {
            ParseTimeData.ParentBuilder = parentBuilder; 
            if ((ParseTimeData.FirstNonThemableProperty != null) && (parentBuilder is FileLevelPageThemeBuilder)) {
                throw new InvalidOperationException(SR.GetString(SR.Property_theme_disabled, ParseTimeData.FirstNonThemableProperty.Name, ControlType.FullName)); 
            } 
        }
 
        //
        public string GetResourceKey() {

            // This should only be used in the designer 
            Debug.Assert(InDesigner);
 
            return ParseTimeData.ResourceKeyPrefix; 
        }
 
        //
        public void SetResourceKey(string resourceKey) {

            // This should only be used in the designer 
            Debug.Assert(InDesigner);
 
            SimplePropertyEntry entry = new SimplePropertyEntry(); 
            entry.Filter = "meta";
            entry.Name = "resourcekey"; 
            entry.Value = resourceKey;
            entry.PersistedValue = resourceKey;
            entry.UseSetAttribute = true;
            entry.Type = typeof(string); 

            AddEntry(SimplePropertyEntriesInternal, entry); 
        } 

 
        /// 
        ///  Give the builder the raw inner text of the tag.
        /// 
        public virtual void SetTagInnerText(string text) { 
        }
 
        ///  
        ///  Give the ControlBuilder a chance to look at and modify the tree
        ///  
        public virtual void ProcessGeneratedCode(
            CodeCompileUnit codeCompileUnit,
            CodeTypeDeclaration baseType,
            CodeTypeDeclaration derivedType, 
            CodeMemberMethod buildMethod,
            CodeMemberMethod dataBindingMethod) { } 
 
        /// 
        /// Make sure the given property with the specified context (using SetAttribute to set the value or a directive property) is persistable 
        /// throwing otherwise
        /// 
        private void ValidatePersistable(PropertyInfo propInfo, bool usingSetAttribute,
            bool mainDirectiveMode, bool simplePropertyEntry, string filter) { 

            // Get the appropriate PropertyDescriptorCollection.  If it's for our own type, just 
            // call our PropertyDescriptors property, which caches it.  Otherwise (for sub properties) 
            // get it directly without caching (less common case).
            PropertyDescriptorCollection propertyDescriptors; 

            // Use the current control type if it derives from propInfo.DeclaringType
            bool useCurrentControlType = propInfo.DeclaringType.IsAssignableFrom(_controlType);
 
            if (useCurrentControlType) {
                propertyDescriptors = PropertyDescriptors; 
            } 
            else {
                // See comments below regarding when we 
                propertyDescriptors = TypeDescriptor.GetProperties(propInfo.DeclaringType);
            }

            PropertyDescriptor propDesc = propertyDescriptors[propInfo.Name]; 

            if (propDesc != null) { 
                if (useCurrentControlType) { 
                    // These checks are only done for top-level properties (e.g. Text="hello").
                    // We don't do it for sub-properties (e.g. Font-Name="Arial") since it would 
                    // break backwards compatibility with v1.1 (where we did not do these checks).

                    // If it's an HtmlControl,
                    if (IsHtmlControl) { 
                        if (propDesc.Attributes.Contains(HtmlControlPersistableAttribute.No)) {
                            throw new HttpException(SR.GetString(SR.Property_Not_Persistable, propDesc.Name)); 
                        } 
                    }
                    // Otherwise, if we're not using the attribute accessor, we're not processing the main directive 
                    //
                    else if (!usingSetAttribute && !mainDirectiveMode && propDesc.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden)) {
                        throw new HttpException(SR.GetString(SR.Property_Not_Persistable, propDesc.Name));
                    } 
                }
 
                // These checks are done for both top-level properties, as well as sub-properties. 
                // Backwards compatibility is satisfied since the Filterable() and Themeable()
                // attributes are new in v2.0. 

                // Make sure the property is filterable if there is a filter
                if (!FilterableAttribute.IsPropertyFilterable(propDesc) && !String.IsNullOrEmpty(filter)) {
                    throw new InvalidOperationException(SR.GetString(SR.Illegal_Device, propDesc.Name)); 
                }
 
                if (InPageTheme && (ParseTimeData.FirstNonThemableProperty == null)) { 
                    // For simple properties, don't validate if it's a customAttribute
                    if (!simplePropertyEntry || !usingSetAttribute) { 
                        ThemeableAttribute attr = (ThemeableAttribute)propDesc.Attributes[typeof(ThemeableAttribute)];
                        if (attr != null && !attr.Themeable) {
                            if (this.ParentBuilder != null) {
                                if (ParentBuilder is FileLevelPageThemeBuilder) { 
                                    throw new InvalidOperationException(SR.GetString(SR.Property_theme_disabled, propDesc.Name, ControlType.FullName));
                                } 
                            } 
                            else {
                                ParseTimeData.FirstNonThemableProperty = propDesc; 
                            }
                        }
                    }
                } 
            }
        } 
 
        // Default factory used create base ControlBuilder objects
        private static IWebObjectFactory s_defaultControlBuilderFactory = new DefaultControlBuilderFactory(); 

        private class DefaultControlBuilderFactory : IWebObjectFactory {
            object IWebObjectFactory.CreateInstance() {
                return new ControlBuilder(); 
            }
        } 
 
        // Factories used when we cannot generate a fast factory (e.g. because the ControlBuilder
        // type is internal). 
        private class ReflectionBasedControlBuilderFactory : IWebObjectFactory {
            private Type _builderType;

            internal ReflectionBasedControlBuilderFactory(Type builderType) { 
                _builderType = builderType;
            } 
 
            object IWebObjectFactory.CreateInstance() {
                return (ControlBuilder)HttpRuntime.CreateNonPublicInstance(_builderType); 
            }
        }

        ///  
        /// Space-saving class used to store variables used only during parse and codegen time.
        /// All these are cleared when the ControlBuilder is used in a no-compile page. 
        ///  
        private sealed class ControlBuilderParseTimeData {
 
            // const masks into the BitVector32
            private const int childrenAsProperties = 0x00000001;
            private const int hasAspCode = 0x00000002;
            private const int isHtmlControl = 0x00000004; 
            private const int isNonParserAccessor = 0x00000008;
            private const int namingContainerSearched = 0x00000010; 
            private const int supportsAttributes = 0x00000020; 
            private const int isGeneratedID = 0x00000040;
            private const int localize = 0x00000080; 
            private const int ignoreControlProperties = 0x00000100;
            #pragma warning disable 0649
            private SimpleBitVector32 flags;
            #pragma warning restore 0649 

            internal bool ChildrenAsProperties { 
                get { return flags[childrenAsProperties]; } 
                set { flags[childrenAsProperties] = value; }
            } 

            internal ControlBuilder DefaultPropertyBuilder;

            internal EventDescriptorCollection EventDescriptors; 

            internal string Filter; 
 
            internal bool HasAspCode {
                get { return flags[hasAspCode]; } 
                set { flags[hasAspCode] = value; }
            }

            internal bool IsHtmlControl { 
                get { return flags[isHtmlControl]; }
                set { flags[isHtmlControl] = value; } 
            } 

            internal bool IgnoreControlProperties { 
                get { return flags[ignoreControlProperties]; }
                set { flags[ignoreControlProperties] = value; }
            }
 
            internal bool IsNonParserAccessor {
                get { return flags[isNonParserAccessor]; } 
                set { flags[isNonParserAccessor] = value; } 
            }
 
            internal bool IsGeneratedID {
                get { return flags[isGeneratedID]; }
                set { flags[isGeneratedID] = value; }
            } 

            internal string ID; 
 
            internal int Line;
 
            internal bool Localize {
                get { return flags[localize]; }
                set { flags[localize] = value; }
            } 

            internal bool NamingContainerSearched { 
                get { return flags[namingContainerSearched]; } 
                set { flags[namingContainerSearched] = value; }
            } 

            internal ControlBuilder NamingContainerBuilder;

            internal ControlBuilder ParentBuilder; 

            internal TemplateParser Parser; 
 
            internal PropertyDescriptorCollection PropertyDescriptors;
 
            internal StringSet PropertyEntries;

            internal bool SupportsAttributes {
                get { return flags[supportsAttributes]; } 
                set { flags[supportsAttributes] = value; }
            } 
 
            internal VirtualPath VirtualPath;
 
            internal PropertyDescriptor FirstNonThemableProperty;

            internal string ResourceKeyPrefix;
        } 

        internal sealed class FilteredPropertyEntryComparer : IComparer { 
            IFilterResolutionService _filterResolutionService; 

            public FilteredPropertyEntryComparer(IFilterResolutionService filterResolutionService) { 
                _filterResolutionService = filterResolutionService;
            }

            int IComparer.Compare(object o1, object o2) { 
                if (o1 == o2) {
                    return 0; 
                } 

                if (o1 == null) { 
                    return 1;
                }

                if (o2 == null) { 
                    return -1;
                } 
 
                Debug.Assert(o1 is PropertyEntry);
                Debug.Assert(o2 is PropertyEntry); 

                PropertyEntry entry1 = (PropertyEntry)o1;
                PropertyEntry entry2 = (PropertyEntry)o2;
 
                // Compare the order of the item to make the sorting stable.
                int compareValue = entry1.Order - entry2.Order; 
 
                if (compareValue == 0) {
                    if (_filterResolutionService == null) { 
                        if (String.IsNullOrEmpty(entry1.Filter)) {
                            if ((entry2.Filter != null) && (entry2.Filter.Length > 0)) {
                                compareValue = 1;
                            } 
                            else {
                                compareValue = 0; 
                            } 
                        }
                        else { 
                            if (String.IsNullOrEmpty(entry2.Filter)) {
                                compareValue = -1;
                            }
                            else { 
                                compareValue = 0;
                            } 
                        } 
                    }
                    else { 
                        string filter1 = (entry1.Filter.Length == 0) ? "Default" : entry1.Filter;
                        string filter2 = (entry2.Filter.Length == 0) ? "Default" : entry2.Filter;

                        compareValue = _filterResolutionService.CompareFilters(filter1, filter2); 
                    }
 
                    // Compare the index of the item in the array to make the sorting stable. 
                    if (compareValue == 0) {
                        return entry1.Index - entry2.Index; 
                    }
                }

                return compareValue; 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK