GridEntry.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyGridInternal / GridEntry.cs / 2 / GridEntry.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

//#define PBRS_PAINT_DEBUG 
/* 
 */
namespace System.Windows.Forms.PropertyGridInternal { 
    using System.Security.Permissions;
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Remoting;
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System; 
    using System.Collections;
    using System.Reflection; 
    using System.Globalization;

    using System.Drawing.Design;
    using System.ComponentModel.Design; 
    using System.Windows.Forms;
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.Internal; 
    using System.Drawing;
    using System.Drawing.Drawing2D; 
    using Microsoft.Win32;

    /// 
    ///  
    ///     Base Entry for properties to be displayed in properties window.
    ///  
    internal abstract class GridEntry : GridItem, ITypeDescriptorContext { 

        protected static readonly Point InvalidPoint = new Point(int.MinValue, int.MinValue); 
        private static BooleanSwitch PbrsAssertPropsSwitch = new BooleanSwitch("PbrsAssertProps", "PropertyBrowser : Assert on broken properties");

        internal static AttributeTypeSorter AttributeTypeSorter = new AttributeTypeSorter();
 
        // Type flags
        internal const int FLAG_TEXT_EDITABLE             = 0x0001; 
        internal const int FLAG_ENUMERABLE                = 0x0002; 
        internal const int FLAG_CUSTOM_PAINT              = 0x0004;
        internal const int FLAG_IMMEDIATELY_EDITABLE      = 0x0008; 
        internal const int FLAG_CUSTOM_EDITABLE           = 0x0010;
        internal const int FLAG_DROPDOWN_EDITABLE         = 0x0020;
        internal const int FLAG_LABEL_BOLD                = 0x0040;
        internal const int FLAG_READONLY_EDITABLE         = 0x0080; 
        internal const int FLAG_RENDER_READONLY           = 0x0100;
        internal const int FLAG_IMMUTABLE                 = 0x0200; 
        internal const int FLAG_FORCE_READONLY            = 0x0400; 
        internal const int FLAG_RENDER_PASSWORD           = 0x1000;
 
        internal const int FLAG_DISPOSED                  = 0x2000;

        internal const int FL_EXPAND                   = 0x00010000;
        internal const int FL_EXPANDABLE               = 0x00020000; 
        //protected const int FL_EXPANDABLE_VALID         = 0x00040000;
        internal const int FL_EXPANDABLE_FAILED        = 0x00080000; 
        internal const int FL_NO_CUSTOM_PAINT          = 0x00100000; 
        internal const int FL_CATEGORIES               = 0x00200000;
        internal const int FL_CHECKED                  = unchecked((int)0x80000000); 

        // rest are GridEntry constants.

        protected const int NOTIFY_RESET                = 1; 
        protected const int NOTIFY_CAN_RESET            = 2;
        protected const int NOTIFY_DBL_CLICK            = 3; 
        protected const int NOTIFY_SHOULD_PERSIST       = 4; 
        protected const int NOTIFY_RETURN               = 5;
 
        protected const int     OUTLINE_ICON_PADDING    = 5;

        protected static IComparer DisplayNameComparer    = new DisplayNameSortComparer();
 
        private static char passwordReplaceChar;
        //Maximum number of characters we'll show in the property grid.  Too many characters leads 
        //to bad performance. 
        private const int maximumLengthOfPropertyString = 1000;
 
        [Flags]
        internal enum PaintValueFlags{
            None = 0,
            DrawSelected = 0x1, 
            FetchValue   = 0x2,
            CheckShouldSerialize = 0x4, 
            PaintInPlace = 0x8 
        }
 
        private class CacheItems {
            public string lastLabel;
            public Font   lastLabelFont;
            public int    lastLabelWidth; 
            public string lastValueString;
            public Font   lastValueFont; 
            public int    lastValueTextWidth; 
            public object lastValue;
            public bool   useValueString; 
            public bool   lastShouldSerialize;
            public bool   useShouldSerialize;
            public bool   useCompatTextRendering;
        } 

        private CacheItems cacheItems; 
 

        // instance variables. 
        protected TypeConverter     converter     = null;
        protected UITypeEditor      editor        = null;
        internal  GridEntry         parentPE      = null;
        private   GridEntryCollection childCollection = null; 
        internal  int               flags         = 0;
        private   int               propertyDepth = 0; 
        protected bool              hasFocus      = false; 
        private   Rectangle         outlineRect   = Rectangle.Empty;
        protected PropertySort      PropertySort; 

        protected Point             labelTipPoint = InvalidPoint;
        protected Point             valueTipPoint = InvalidPoint;
 
        protected PropertyGrid      ownerGrid;
 
        private   static object      EVENT_VALUE_CLICK = new object(); 
        private   static object      EVENT_LABEL_CLICK = new object();
        private   static object      EVENT_OUTLINE_CLICK = new object(); 
        private   static object      EVENT_VALUE_DBLCLICK = new object();
        private   static object      EVENT_LABEL_DBLCLICK = new object();
        private   static object      EVENT_OUTLINE_DBLCLICK = new object();
        private   static object      EVENT_RECREATE_CHILDREN = new object(); 

        private GridEntryAccessibleObject accessibleObject = null; 
 
        protected GridEntry(PropertyGrid owner, GridEntry peParent) {
            parentPE = peParent; 
            ownerGrid = owner;

            Debug.Assert( this.ownerGrid != null, "GridEntry w/o PropertyGrid owner, text rendering will fail." );
 
            if (peParent != null) {
                propertyDepth = peParent.PropertyDepth + 1; 
                this.PropertySort = peParent.PropertySort; 

                if (peParent.ForceReadOnly) { 
                    flags |= FLAG_FORCE_READONLY;
                }

            } 
            else {
                propertyDepth = -1; 
            } 
        }
 

        public AccessibleObject AccessibilityObject {

            get { 
                if (accessibleObject == null) {
                    accessibleObject = new GridEntryAccessibleObject(this); 
                } 
                return accessibleObject;
            } 
        }

        /// 
        ///  
        /// specify that this grid entry should be allowed to be merged for.
        /// multi-select. 
        ///  
        public virtual bool AllowMerge {
            get { 
                return true;
            }
        }
 
        internal virtual bool AlwaysAllowExpand {
            get { 
               return false; 
            }
        } 

        internal virtual AttributeCollection Attributes {
            get {
                return TypeDescriptor.GetAttributes(PropertyType); 
            }
        } 
 
        /// 
        ///  
        /// Gets the value of the background brush to use.  Override
        /// this member to cause the entry to paint it's background in a different color.
        /// The base implementation returns null.
        ///  
        protected virtual Brush GetBackgroundBrush(Graphics g) {
            return GridEntryHost.GetBackgroundBrush(g); 
        } 

        ///  
        /// 
        /// 
        protected virtual Color LabelTextColor {
            get { 
                if (this.ShouldRenderReadOnly) {
                    return GridEntryHost.GrayTextColor; 
                } 
                else {
                    return GridEntryHost.GetTextColor(); 
                }
            }
        }
 
        /// 
        ///  
        /// The set of attributes that will be used for browse filtering 
        /// 
        public virtual AttributeCollection BrowsableAttributes { 
            get{
                if (parentPE != null) {
                    return parentPE.BrowsableAttributes;
                } 
                return null;
            } 
            set{ 
                parentPE.BrowsableAttributes = value;
            } 
        }

        /// 
        ///  
        ///      Retrieves the component that is invoking the
        ///      method on the formatter object.  This may 
        ///      return null if there is no component 
        ///      responsible for the call.
        ///  
        public virtual IComponent Component {
            get {
                object owner = GetValueOwner();
                if (owner is IComponent) { 
                    return(IComponent) owner;
                } 
                if (parentPE != null) { 
                    return parentPE.Component;
                } 
                return null;
            }
        }
 
        protected virtual IComponentChangeService ComponentChangeService {
            get { 
                return parentPE.ComponentChangeService; 
            }
 
        }

        /// 
        ///  
        ///      Retrieves the container that contains the
        ///      set of objects this formatter may work 
        ///      with.  It may return null if there is no 
        ///      container, or of the formatter should not
        ///      use any outside objects. 
        /// 
        public virtual IContainer Container {
            get {
                IComponent component = Component; 
                if (component != null) {
                    ISite site = component.Site; 
                    if (site != null) { 
                        return site.Container;
                    } 
                }
                return null;
            }
        } 

        protected GridEntryCollection ChildCollection{ 
            get { 
                if (childCollection == null) {
                    childCollection = new GridEntryCollection(this, null); 
                }
                return childCollection;
            }
            set { 
                Debug.Assert(value == null || !Disposed, "Why are we putting new children in after we are disposed?");
                if (this.childCollection != value) { 
                    if (this.childCollection != null) { 
                        this.childCollection.Dispose();
                        this.childCollection = null; 
                    }
                    this.childCollection = value;
                }
            } 
        }
 
        public int ChildCount { 
            get {
                if (Children != null) { 
                    return Children.Count;
                }
                return 0;
            } 
        }
 
        public virtual GridEntryCollection Children { 
            get {
                if (childCollection == null && !Disposed) { 
                    CreateChildren();
                }
                return childCollection;
            } 
        }
 
        public virtual PropertyTab CurrentTab{ 
            get{
                if (parentPE != null) { 
                    return parentPE.CurrentTab;
                }
                return null;
            } 
            set{
                if (parentPE != null) { 
                    parentPE.CurrentTab = value; 
                }
            } 
        }

        /// 
        ///  
        /// Returns the default child GridEntry of this item.  Usually the default property
        /// of the target object. 
        ///  
        internal virtual GridEntry DefaultChild {
            get { 
                return null;
            }
            set{}
        } 

        internal virtual IDesignerHost DesignerHost{ 
            get{ 
                if (parentPE != null) {
                    return parentPE.DesignerHost; 
                }
                return null;
            }
            set { 
                if (parentPE != null) {
                    parentPE.DesignerHost = value; 
                } 
            }
        } 

        internal bool Disposed{
            get {
                return GetFlagSet(FLAG_DISPOSED); 
            }
        } 
 
        internal virtual bool Enumerable {
            get { 
                return(this.Flags & GridEntry.FLAG_ENUMERABLE) != 0;
            }
        }
 

        public override bool Expandable { 
            get { 
                bool fExpandable = GetFlagSet(FL_EXPANDABLE);
 
                if (fExpandable && childCollection != null && childCollection.Count > 0) {
                    return true;
                }
 
                if (GetFlagSet(FL_EXPANDABLE_FAILED)) {
                    return false; 
                } 

                if (fExpandable && (cacheItems == null || cacheItems.lastValue == null) && this.PropertyValue == null) { 
                    fExpandable = false;
                }

                return fExpandable; 
            }
        } 
 
        public override bool Expanded {
            get{ 
                return InternalExpanded;
            }
            set {
                GridEntryHost.SetExpand(this, value); 
            }
        } 
 
        internal virtual bool ForceReadOnly {
            get { 
                return (flags & FLAG_FORCE_READONLY) != 0;
            }
        }
 
         internal virtual bool InternalExpanded {
            get{ 
                // short circuit if we don't have children 
                if (childCollection == null || childCollection.Count == 0) {
                    return false; 
                }
                return GetFlagSet(FL_EXPAND);
            }
            set { 
                if (!this.Expandable || value == this.InternalExpanded) {
                    return; 
                } 

                if (childCollection != null && childCollection.Count > 0) { 
                    SetFlag(FL_EXPAND,value);
                }
                else {
                    SetFlag(FL_EXPAND,false); 
                    if (value) {
                        bool fMakeSure = CreateChildren(); 
                        SetFlag(FL_EXPAND,fMakeSure); 
                    }
                } 
            }
        }

        internal virtual int Flags { 
            get {
                if ((flags & FL_CHECKED) != 0) { 
                    return flags; 
                }
 
                flags |= FL_CHECKED;

                TypeConverter converter = TypeConverter;
                UITypeEditor  uiEditor  = UITypeEditor; 
                object value = Instance;
                bool forceReadOnly = this.ForceReadOnly; 
 
                if (value != null) {
                     forceReadOnly |= TypeDescriptor.GetAttributes(value).Contains(InheritanceAttribute.InheritedReadOnly); 
                }

                if (converter.GetStandardValuesSupported(this)) {
                    flags |= GridEntry.FLAG_ENUMERABLE; 
                }
 
                if (!forceReadOnly && converter.CanConvertFrom(this, typeof(string)) && 
                    !converter.GetStandardValuesExclusive(this)) {
                    flags |= GridEntry.FLAG_TEXT_EDITABLE; 
                }

                bool isImmutableReadOnly = TypeDescriptor.GetAttributes(this.PropertyType)[typeof(ImmutableObjectAttribute)].Equals(ImmutableObjectAttribute.Yes);
                bool isImmutable = isImmutableReadOnly || converter.GetCreateInstanceSupported(this); 

                if (isImmutable) { 
                    flags |= GridEntry.FLAG_IMMUTABLE; 
                }
 
                if (converter.GetPropertiesSupported(this)) {
                    flags |= GridEntry.FL_EXPANDABLE;

                    // If we're exapndable, but we don't support editing, 
                    // make us read only editable so we don't paint grey.
                    // 
                    if (!forceReadOnly && (flags & GridEntry.FLAG_TEXT_EDITABLE) == 0 && !isImmutableReadOnly) { 
                        flags |= GridEntry.FLAG_READONLY_EDITABLE;
                    } 
                }

                if (Attributes.Contains(PasswordPropertyTextAttribute.Yes)) {
                    flags |= GridEntry.FLAG_RENDER_PASSWORD; 
                }
 
                if (uiEditor != null) { 
                    if (uiEditor.GetPaintValueSupported(this)) {
                        flags |= GridEntry.FLAG_CUSTOM_PAINT; 
                    }

                    // We only allow drop-downs if the object is NOT being inherited
                    // I would really rather this not be here, but we have other places where 
                    // we make read-only properties editable if they have drop downs.  Not
                    // sure this is the right thing...is it? 
 
                    bool allowButtons = !forceReadOnly;
 
                    if (allowButtons) {
                        switch (uiEditor.GetEditStyle(this)) {
                            case UITypeEditorEditStyle.Modal:
                                flags |= GridEntry.FLAG_CUSTOM_EDITABLE; 
                                if (!isImmutable && !PropertyType.IsValueType) {
                                    flags |= GridEntry.FLAG_READONLY_EDITABLE; 
                                } 
                                break;
                            case UITypeEditorEditStyle.DropDown: 
                                flags |= GridEntry.FLAG_DROPDOWN_EDITABLE;
                                break;
                        }
                    } 
                }
 
                return flags; 

            } 
            set {
                flags = value;
            }
        } 

        ///  
        ///  
        /// Checks if the entry is currently expanded
        ///  
        public bool Focus {
            get{
                return this.hasFocus;
            } 
            set{
 
                if (Disposed) { 
                    return;
                } 

                if (cacheItems != null) {
                    cacheItems.lastValueString = null;
                    cacheItems.useValueString = false; 
                    cacheItems.useShouldSerialize = false;
                } 
 
                if (this.hasFocus != value) {
                    this.hasFocus = value; 

                    // Notify accessibility applications that keyboard focus has changed.
                    //
                    if (value == true) { 
                        int id = ((PropertyGridView)GridEntryHost).AccessibilityGetGridEntryChildID(this);
                        if (id >= 0) { 
                            PropertyGridView.PropertyGridViewAccessibleObject gridAccObj = 
                                (PropertyGridView.PropertyGridViewAccessibleObject)((PropertyGridView)GridEntryHost).AccessibilityObject;
 
                            gridAccObj.NotifyClients(AccessibleEvents.Focus, id);
                            gridAccObj.NotifyClients(AccessibleEvents.Selection, id);
                        }
                    } 
                }
            } 
        } 

        ///  
        /// 
        /// Returns the label including the object name, and properties.  For example, the value
        /// of the Font size property on a Button called Button1 would be "Button1.Font.Size"
        ///  
        public string FullLabel {
            get { 
                string str = null; 
                if (parentPE != null) {
                    str = parentPE.FullLabel; 
                }

                if (str != null) {
                    str += "."; 
                }
                else { 
                    str = ""; 
                }
                str += this.PropertyLabel; 

                return str;
            }
        } 

        public override GridItemCollection GridItems { 
            get { 
                if (Disposed) {
                    throw new ObjectDisposedException(SR.GetString(SR.GridItemDisposed)); 
                }

                if (IsExpandable && childCollection != null && childCollection.Count == 0) {
                    CreateChildren(); 
                }
 
                return this.Children; 
            }
        } 

        internal virtual PropertyGridView GridEntryHost{
            get{        // ACCESSOR: virtual was missing from this get
                if (parentPE != null) { 
                    return parentPE.GridEntryHost;
                } 
                return null; 
            }
            set { 
                throw new NotSupportedException();
            }
        }
 
        public override GridItemType GridItemType {
            get { 
                return GridItemType.Property; 
            }
        } 

        /// 
        /// 
        /// Returns true if this GridEntry has a value field in the right hand column. 
        /// 
        internal virtual bool HasValue { 
            get { 
                return true;
            } 
        }

        /// 
        ///  
        ///     Retrieves the keyword that the VS help dynamic help window will
        ///     use when this IPE is selected. 
        ///  
        public virtual string HelpKeyword {
            get { 
                string keyWord = null;

                if (parentPE != null) {
                    keyWord = parentPE.HelpKeyword; 
                }
                if (keyWord == null) { 
                    keyWord = String.Empty; 
                }
 
                return keyWord;
            }
        }
 
        internal virtual string HelpKeywordInternal{
            get { 
               return this.HelpKeyword; 
            }
        } 

        public virtual bool IsCustomPaint {
            get {
                // prevent full flag population if possible. 
                if ((flags & FL_CHECKED) == 0) {
                    UITypeEditor typeEd = this.UITypeEditor; 
                    if (typeEd != null) { 
                        if ((this.flags & GridEntry.FLAG_CUSTOM_PAINT) != 0 ||
                            (this.flags & GridEntry.FL_NO_CUSTOM_PAINT) != 0) { 
                            return(this.flags & GridEntry.FLAG_CUSTOM_PAINT) != 0;
                        }

 
                        if (typeEd.GetPaintValueSupported(this)) {
                            flags |= GridEntry.FLAG_CUSTOM_PAINT; 
                            return true; 
                        }
                        else { 
                            flags |= GridEntry.FL_NO_CUSTOM_PAINT;
                            return false;
                        }
                    } 
                }
                return(this.Flags & GridEntry.FLAG_CUSTOM_PAINT) != 0; 
            } 
        }
 
        public virtual bool IsExpandable {
            get {
                return this.Expandable;
            } 
            set {
                if (value != GetFlagSet(FL_EXPANDABLE)) { 
                    SetFlag(FL_EXPANDABLE_FAILED, false); 
                    SetFlag(FL_EXPANDABLE, value);
                } 
            }
        }

        public virtual bool IsTextEditable { 
            get {
                return this.IsValueEditable && (this.Flags & GridEntry.FLAG_TEXT_EDITABLE) != 0; 
            } 
        }
 
        public virtual bool IsValueEditable {
            get {
                return !ForceReadOnly && 0 != (Flags & (GridEntry.FLAG_DROPDOWN_EDITABLE | GridEntry.FLAG_TEXT_EDITABLE | GridEntry.FLAG_CUSTOM_EDITABLE | GridEntry.FLAG_ENUMERABLE));
            } 
        }
 
        ///  
        /// 
        ///      Retrieves the component that is invoking the 
        ///      method on the formatter object.  This may
        ///      return null if there is no component
        ///      responsible for the call.
        ///  
        public virtual object Instance {
            get { 
                object owner = GetValueOwner(); 

                if (parentPE != null && owner == null) { 
                    return parentPE.Instance;
                }
                return owner;
            } 
        }
 
        public override string Label { 
            get {
                return this.PropertyLabel; 
            }
        }

        ///  
        /// 
        ///      Retrieves the PropertyDescriptor that is surfacing the given object/ 
        ///  
        public override PropertyDescriptor PropertyDescriptor {
            get { 
                return null;
            }
        }
 

 
        ///  
        /// 
        /// Returns the pixel indent of the current GridEntry's label. 
        /// 
        internal virtual int PropertyLabelIndent {
            get {
                int borderWidth = this.GridEntryHost.GetOutlineIconSize() + OUTLINE_ICON_PADDING; 
                return((propertyDepth + 1) * borderWidth) + 1;
            } 
        } 

        internal virtual Point GetLabelToolTipLocation(int mouseX, int mouseY) { 
            return labelTipPoint;
        }

        internal virtual string LabelToolTipText { 
            get {
                return this.PropertyLabel; 
            } 
        }
 
        public virtual bool NeedsDropDownButton{
            get {
                return(this.Flags & GridEntry.FLAG_DROPDOWN_EDITABLE) != 0;
            } 
        }
 
        public virtual bool NeedsCustomEditorButton{ 
            get {
                return(this.Flags & GridEntry.FLAG_CUSTOM_EDITABLE) != 0 && (IsValueEditable || (Flags & GridEntry.FLAG_READONLY_EDITABLE) !=0); 
            }
        }

        public PropertyGrid OwnerGrid{ 
            get{
                return this.ownerGrid; 
            } 
        }
 
            /// 
            /// 
            /// Returns rect that the outline icon (+ or - or arrow) will be drawn into, relative
            /// to the upper left corner of the GridEntry. 
            /// 
            public Rectangle OutlineRect { 
            get { 
                if (!outlineRect.IsEmpty) {
                    return outlineRect; 
                }
                PropertyGridView gridHost = this.GridEntryHost;
                Debug.Assert(gridHost != null, "No propEntryHost!");
                int outlineSize = gridHost.GetOutlineIconSize(); 
                int borderWidth = outlineSize + OUTLINE_ICON_PADDING;
                int left = (propertyDepth*borderWidth) + (OUTLINE_ICON_PADDING)/2;//+ 1; 
                int top =  (gridHost.GetGridEntryHeight() - outlineSize)/2;// - 1;  // figure out edit positioning. 
                outlineRect = new Rectangle(left, top, outlineSize, outlineSize);
                return outlineRect; 
            }
        }

        public virtual GridEntry ParentGridEntry{ 
            get {
                return this.parentPE; 
            } 
            set {
                Debug.Assert(value != this, "how can we be our own parent?"); 
                this.parentPE = value;
                if (value != null) {
                    propertyDepth = value.PropertyDepth+1;
 
                    // [....], why do we do this?
                    if (this.childCollection != null) { 
                        for (int i = 0; i < childCollection.Count; i++) { 
                            childCollection.GetEntry(i).ParentGridEntry = this;
                        } 
                    }
                }
            }
        } 

        public override GridItem Parent { 
            get { 
                if (Disposed) {
                    throw new ObjectDisposedException(SR.GetString(SR.GridItemDisposed)); 
                }

                GridItem parent = this.ParentGridEntry;
 
                // don't allow walking all the way up to the parent.
                // 
                //if (parent is IRootGridEntry) { 
                //    return null;
                //} 
                return parent;
            }
        }
 
        /// 
        ///  
        /// Returns category name of the current property 
        /// 
        public virtual string PropertyCategory { 
            get {
                return CategoryAttribute.Default.Category;
            }
        } 

        ///  
        ///  
        /// Returns "depth" of this property.  That is, how many parent's between
        /// this property and the root property.  The root property has a depth of -1. 
        /// 
        public virtual int PropertyDepth {
            get {
                return propertyDepth; 
            }
        } 
 

        ///  
        /// 
        /// Returns the description helpstring for this GridEntry.
        /// 
        public virtual string PropertyDescription { 
            get {
                return null; 
            } 
        }
 
        /// 
        /// 
        /// Returns the label of this property.  Usually
        /// this is the property name. 
        /// 
        public virtual string PropertyLabel { 
            get { 
                return null;
            } 
        }

        /// 
        ///  
        /// Returns non-localized name of this property.
        ///  
        public virtual string PropertyName { 
            get {
                return this.PropertyLabel; 
            }
        }

        ///  
        /// 
        /// Returns the Type of the value of this GridEntry, or null if the value is null. 
        ///  
        public virtual Type PropertyType {
            get { 
                object obj = this.PropertyValue;
                if (obj != null) {
                    return obj.GetType();
                } 
                else {
                    return null; 
                } 
            }
        } 

        /// 
        /// 
        /// Gets or sets the value for the property that is represented 
        /// by this GridEntry.
        ///  
        public virtual object PropertyValue{ 
            get {
                if (cacheItems != null) { 
                    return cacheItems.lastValue;
                }
                return null;
            } 
            set {
            } 
        } 

        public virtual bool ShouldRenderPassword { 
            get {
                return (this.Flags & GridEntry.FLAG_RENDER_PASSWORD) != 0;
            }
        } 

        public virtual bool ShouldRenderReadOnly { 
            get { 
                return ForceReadOnly || (0 != (this.Flags & GridEntry.FLAG_RENDER_READONLY) || (!this.IsValueEditable && (0 == (this.Flags & GridEntry.FLAG_READONLY_EDITABLE))));
            } 
        }

        /// 
        ///  
        /// Returns the type converter for this entry.
        ///  
        internal virtual TypeConverter TypeConverter { 
            get {
                if (converter == null) { 
                    object value = this.PropertyValue;
                    if (value == null) {
                        converter = TypeDescriptor.GetConverter(this.PropertyType);
                    } 
                    else {
                        converter = TypeDescriptor.GetConverter(value); 
                    } 
                }
                return converter; 
            }
        }

        ///  
        /// 
        /// Returns the type editor for this entry.  This may return null if there 
        /// is no type editor. 
        /// 
        internal virtual UITypeEditor UITypeEditor { 
            get {
                if (editor == null && this.PropertyType != null) {
                    editor = (UITypeEditor)TypeDescriptor.GetEditor(this.PropertyType, typeof(System.Drawing.Design.UITypeEditor));
                } 

                return editor; 
            } 
        }
 
        public override object Value {
            get {
                return this.PropertyValue;
            } 
            // note: we don't do set because of the value class semantics, etc.
        } 
 
        internal Point ValueToolTipLocation {
            get { 
                return ShouldRenderPassword ? InvalidPoint : valueTipPoint;
            }
            set{
                valueTipPoint = value; 
            }
        } 
 
        internal int VisibleChildCount {
            get{ 
                if (!Expanded) {
                    return 0;
                }
                int count = ChildCount; 
                int totalCount = count;
                for (int i = 0; i < count; i++) { 
                     totalCount += ChildCollection.GetEntry(i).VisibleChildCount; 
                }
                return totalCount; 
            }
        }

 
        /// 
        ///  
        /// Add an event handler to be invoked when the label portion of 
        /// the prop entry is clicked
        ///  
        public virtual void AddOnLabelClick(EventHandler h) {
            AddEventHandler(EVENT_LABEL_CLICK, h);
        }
 
        /// 
        ///  
        /// Add an event handler to be invoked when the label portion of 
        /// the prop entry is double
        ///  
        public virtual void AddOnLabelDoubleClick(EventHandler h) {
            AddEventHandler(EVENT_LABEL_DBLCLICK, h);
        }
 
        /// 
        ///  
        /// Add an event handler to be invoked when the value portion of 
        /// the prop entry is clicked
        ///  
        public virtual void AddOnValueClick(EventHandler h) {
            AddEventHandler(EVENT_VALUE_CLICK, h);
        }
 

        ///  
        ///  
        /// Add an event handler to be invoked when the value portion of
        /// the prop entry is double-clicked 
        /// 
        public virtual void AddOnValueDoubleClick(EventHandler h) {
            AddEventHandler(EVENT_VALUE_DBLCLICK, h);
        } 

        ///  
        ///  
        /// Add an event handler to be invoked when the outline icone portion of
        /// the prop entry is clicked 
        /// 
        public virtual void AddOnOutlineClick(EventHandler h) {
            AddEventHandler(EVENT_OUTLINE_CLICK, h);
        } 

        ///  
        ///  
        /// Add an event handler to be invoked when the outline icone portion of
        /// the prop entry is double clicked 
        /// 
        public virtual void AddOnOutlineDoubleClick(EventHandler h) {
            AddEventHandler(EVENT_OUTLINE_DBLCLICK, h);
        } 

        ///  
        ///  
        /// Add an event handler to be invoked when the children grid entries are re-created.
        ///  
        public virtual void AddOnRecreateChildren(GridEntryRecreateChildrenEventHandler h) {
            AddEventHandler(EVENT_RECREATE_CHILDREN, h);
        }
 
        internal void ClearCachedValues() {
            ClearCachedValues(true); 
        } 

        internal void ClearCachedValues(bool clearChildren) { 
               if (cacheItems != null) {
                  cacheItems.useValueString = false;
                  cacheItems.lastValue = null;
                  cacheItems.useShouldSerialize = false; 
               }
               if (clearChildren) { 
                   for (int i = 0; i < ChildCollection.Count; i++) { 
                       ChildCollection.GetEntry(i).ClearCachedValues();
                   } 
               }
        }

        ///  
        /// 
        /// Converts the given string of text to a value. 
        ///  
        public object ConvertTextToValue(string text) {
            if (TypeConverter.CanConvertFrom(this, typeof(string))) { 
                return TypeConverter.ConvertFromString(this, text);
            }
            return text;
        } 

        ///  
        ///  
        /// Create the base prop entries given an object or set of objects
        ///  
        internal static IRootGridEntry Create(PropertyGridView view, object[] rgobjs, IServiceProvider baseProvider, IDesignerHost currentHost, PropertyTab tab, PropertySort initialSortType) {
            IRootGridEntry pe = null;

            if (rgobjs == null || rgobjs.Length == 0) { 
                return null;
            } 
 
            try
            { 
                if (rgobjs.Length == 1)
                {
                    pe = new SingleSelectRootGridEntry(view, rgobjs[0], baseProvider, currentHost, tab, initialSortType);
                } 
                else
                { 
                    pe = new MultiSelectRootGridEntry(view, rgobjs, baseProvider, currentHost, tab, initialSortType); 
                }
            } 
            catch (Exception e)
            {
                //Debug.fail("Couldn't create a top-level GridEntry");
                Debug.Fail(e.ToString()); 
                throw;
            } 
            return pe; 
        }
 
        /// 
        /// 
        /// Populates the children of this grid entry
        ///  
        protected virtual bool CreateChildren() {
            return CreateChildren(false); 
        } 

        ///  
        /// 
        /// Populates the children of this grid entry
        /// 
        protected virtual bool CreateChildren(bool diffOldChildren) { 

            Debug.Assert(!Disposed, "Why are we creating children after we are disposed?"); 
 
            if (!GetFlagSet(FL_EXPANDABLE)) {
                if (this.childCollection != null) { 
                    this.childCollection.Clear();
                }
                else {
                    this.childCollection = new GridEntryCollection(this, new GridEntry[0]); 
                }
                return false; 
            } 

 
            if (!diffOldChildren && childCollection != null && childCollection.Count > 0) {
                return true;
            }
 

            GridEntry [] childProps    = GetPropEntries(this, 
                                                        this.PropertyValue, 
                                                        this.PropertyType);
 

            bool fExpandable = (childProps != null && childProps.Length > 0);

            if (diffOldChildren && childCollection != null && childCollection.Count > 0) { 
                bool same = true;
                if (childProps.Length == childCollection.Count) { 
                    for (int i = 0; i < childProps.Length; i++) { 
                        if (!childProps[i].NonParentEquals(childCollection[i])) {
                            same = false; 
                            break;
                        }
                    }
                } 
                else {
                    same = false; 
                } 

                if (same) { 
                    return true;
                }
            }
 

 
            if (!fExpandable) { 
                SetFlag(FL_EXPANDABLE_FAILED,true);
                if (this.childCollection != null) { 
                    this.childCollection.Clear();
                }
                else {
                    this.childCollection = new GridEntryCollection(this, new GridEntry[0]); 
                }
 
                if (this.InternalExpanded) { 
                    this.InternalExpanded = false;
                } 

            }
            else {
                if (this.childCollection != null) { 
                    this.childCollection.Clear();
                    this.childCollection.AddRange(childProps); 
                } 
                else {
                    this.childCollection = new GridEntryCollection(this, childProps); 
                }
            }
            return fExpandable;
        } 

        public void Dispose() { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 
        protected virtual void Dispose(bool disposing) {
            // make sure we don't accidentally
            // check flags in this state...
            flags  |= FL_CHECKED; 

            SetFlag(FLAG_DISPOSED, true); 
 
            cacheItems = null;
            converter = null; 
            editor = null;
            accessibleObject = null;

            if (disposing) { 
                DisposeChildren();
            } 
        } 

 
        /// 
        /// 
        /// Disposes the array of children
        ///  
        public virtual void DisposeChildren() {
            if (childCollection != null) { 
                childCollection.Dispose(); 
                childCollection = null;
            } 
        }


        ~GridEntry() { 
            Dispose(false);
        } 
 

        ///  
        /// 
        /// Invokes the type editor for editing this item.
        /// 
        internal virtual void EditPropertyValue(PropertyGridView iva) { 
            if (UITypeEditor != null) {
                try { 
                    // this is another icky part.  since edit value can push a modal loop 
                    // there is a chance that this gridentry will be zombied before
                    // it returns.  make sure we're not disposed. 
                    //
                    object originalValue = this.PropertyValue;
                    object value = UITypeEditor.EditValue(this, (IServiceProvider)(ITypeDescriptorContext)this, originalValue);
 
                    if (Disposed) {
                        return; 
                    } 

                    // Push the new value back into the property 
                    if (value != originalValue && this.IsValueEditable) {
                        iva.CommitValue(this, value);
                    }
 
                    if (this.InternalExpanded) {
                        // QFE#3299: If edited property is expanded to show sub-properties, then we want to 
                        // preserve the expanded states of it and all of its descendants. RecreateChildren() 
                        // has logic that is supposed to do this, but which is fundamentally flawed.
                        PropertyGridView.GridPositionData positionData = GridEntryHost.CaptureGridPositionData(); 
                        this.InternalExpanded = false;
                        RecreateChildren();
                        positionData.Restore(GridEntryHost);
                    } 
                    else {
                        // If edited property has no children or is collapsed, don't need to preserve expanded states. 
                        // This limits the scope of the above QFE fix to just those cases where it is actually required. 
                        RecreateChildren();
                    } 
                }
                catch (Exception e)
                {
                    IUIService uiSvc = (IUIService)GetService(typeof(IUIService)); 
                    if (uiSvc != null)
                    { 
                        uiSvc.ShowError(e); 
                    }
                    else 
                    {
                        RTLAwareMessageBox.Show(GridEntryHost, e.Message, SR.GetString(SR.PBRSErrorTitle), MessageBoxButtons.OK,
                                MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
                    } 
                }
            } 
        } 

        ///  
        /// 
        /// Tests two GridEntries for equality
        /// 
        public override bool Equals(object obj) { 

            if (NonParentEquals(obj)) { 
                return((GridEntry)obj).ParentGridEntry == this.ParentGridEntry; 
            }
            return false; 
        }

        /// 
        ///  
        /// Searches for a value of a given property for a value editor user
        ///  
        public virtual object FindPropertyValue(string propertyName, Type propertyType) { 
            object owner = GetValueOwner();
            PropertyDescriptor property = TypeDescriptor.GetProperties(owner)[propertyName]; 
            if (property != null && property.PropertyType == propertyType) {
                return property.GetValue(owner);
            }
 
            if (parentPE != null)
                return parentPE.FindPropertyValue(propertyName, propertyType); 
 
            return null;
        } 

        /// 
        /// 
        /// Returns the index of a child GridEntry 
        /// 
        internal virtual int GetChildIndex(GridEntry pe) { 
            return this.Children.GetEntry(pe); 
        }
 
        /// 
        /// 
        /// Gets the components that own the current value.  This is usually the value of the
        /// root entry, which is the object being browsed.  Walks up the GridEntry tree 
        /// looking for an owner that is an IComponent
        ///  
        public virtual IComponent[] GetComponents() { 
            IComponent component = Component;
            if (component != null) { 
                return new IComponent[] { component};
            }
            return null;
        } 

        protected int GetLabelTextWidth(string labelText, Graphics g, Font f) { 
 
            if (cacheItems == null) {
                cacheItems = new CacheItems(); 
            }
            else if (cacheItems.useCompatTextRendering == ownerGrid.UseCompatibleTextRendering && cacheItems.lastLabel == labelText && f.Equals(cacheItems.lastLabelFont)) {
                return cacheItems.lastLabelWidth;
            } 

            SizeF textSize = PropertyGrid.MeasureTextHelper.MeasureText( this.ownerGrid, g, labelText, f); 
 
            cacheItems.lastLabelWidth = (int) textSize.Width;
            cacheItems.lastLabel = labelText; 
            cacheItems.lastLabelFont = f;
            cacheItems.useCompatTextRendering = ownerGrid.UseCompatibleTextRendering;

            return cacheItems.lastLabelWidth; 
        }
 
        internal int GetValueTextWidth(string valueString, Graphics g, Font f) { 

            if (cacheItems == null) { 
               cacheItems = new CacheItems();
            }
            else if (cacheItems.lastValueTextWidth != -1 && cacheItems.lastValueString == valueString && f.Equals(cacheItems.lastValueFont)) {
               return cacheItems.lastValueTextWidth; 
            }
 
            // Value text is rendered using GDI directly (No TextRenderer) but measured/adjusted using GDI+ (since previous releases), so don't use MeasureTextHelper. 
            cacheItems.lastValueTextWidth = (int) g.MeasureString(valueString, f).Width;
            cacheItems.lastValueString = valueString; 
            cacheItems.lastValueFont = f;
            return cacheItems.lastValueTextWidth;
        }
        //subhag (66503) To check if text contains multiple lines 
        //
        internal bool GetMultipleLines(string valueString) { 
 
            if (valueString.IndexOf('\n') > 0  ||  valueString.IndexOf('\r') > 0 )
                return true; 
            else
                return false;
        }
        ///  
        /// 
        /// Gets the owner of the current value.  This is usually the value of the 
        /// root entry, which is the object being browsed 
        /// 
        public virtual object GetValueOwner() { 
            if (parentPE == null) {
                return this.PropertyValue;
            }
 
            return parentPE.GetChildValueOwner(this);
        } 
 
        /// 
        ///  
        /// Gets the owners of the current value.  This is usually the value of the
        /// root entry, which is the objects being browsed for a multiselect item
        /// 
        public virtual object[] GetValueOwners() { 
            object owner = GetValueOwner();
            if (owner != null) { 
                return new object[] { owner}; 
            }
            return null; 
        }

        /// 
        ///  
        /// Gets the owner of the current value.  This is usually the value of the
        /// root entry, which is the object being browsed 
        ///  
        public virtual object GetChildValueOwner(GridEntry childEntry) {
 
            /*// make sure this is one of our children
            int index = GetChildIndex(childEntry);

            if (index != -1){ 
               return this.PropertyValue;
            } 
 

            Debug.Fail(childEntry.PropertyLabel + " is not a child of " + this.PropertyLabel); 
            return null;*/
            return this.PropertyValue;
        }
 
        /// 
        ///  
        /// Returns a string with info about the currently selected GridEntry 
        /// 
        public virtual string GetTestingInfo() { 
            string str = "object = (";
            string textVal = GetPropertyTextValue();
            if (textVal == null) {
                textVal = "(null)"; 
            }
            else { 
                // make sure we clear any embedded nulls 
                textVal = textVal.Replace((char)0, ' ');
            } 
            Type type = this.PropertyType;
            if (type==null) {
                type = typeof(object);
            } 
            str += this.FullLabel;
            str += "), property = (" + this.PropertyLabel + "," + type.AssemblyQualifiedName + "), value = " + "[" + textVal + "], expandable = " + this.Expandable.ToString() + ", readOnly = " + ShouldRenderReadOnly;; 
            return str; 
        }
 
        /// 
        /// 
        /// Retrieves the type of the value for this GridEntry
        ///  
        public virtual Type GetValueType() {
            return this.PropertyType; 
        } 

        ///  
        /// 
        /// Returns the child GridEntries for this item.
        /// 
        protected virtual GridEntry[] GetPropEntries(GridEntry peParent, object obj, Type objType) { 

 
            // we don't want to create subprops for null objects. 
            if (obj == null) {
                return null; 
            }

            GridEntry[] entries = null;
 
            Attribute[] attributes = new Attribute[this.BrowsableAttributes.Count];
            this.BrowsableAttributes.CopyTo(attributes, 0); 
 
            PropertyTab tab = this.CurrentTab;
            Debug.Assert(tab != null, "No current tab!"); 

            try
            {
 
                bool forceReadOnly = this.ForceReadOnly;
 
                if (!forceReadOnly) 
                {
                    ReadOnlyAttribute readOnlyAttr = (ReadOnlyAttribute)TypeDescriptor.GetAttributes(obj)[typeof(ReadOnlyAttribute)]; 
                    forceReadOnly = (readOnlyAttr != null && !readOnlyAttr.IsDefaultAttribute());
                }

                // do we want to expose sub properties? 
                //
                if (TypeConverter.GetPropertiesSupported(this) || AlwaysAllowExpand) 
                { 

                    // ask the tab if we have one. 
                    //
                    PropertyDescriptorCollection props = null;
                    PropertyDescriptor defProp = null;
                    if (tab != null) 
                    {
                        props = tab.GetProperties(this, obj, attributes); 
                        defProp = tab.GetDefaultProperty(obj); 
                    }
                    else 
                    {
                        props = TypeConverter.GetProperties(this, obj, attributes);
                        defProp = TypeDescriptor.GetDefaultProperty(obj);
                    } 

                    if (props == null) 
                    { 
                        return null;
                    } 

                    if ((this.PropertySort & PropertySort.Alphabetical) != 0)
                    {
                        if (objType == null || !objType.IsArray) 
                        {
                            props = props.Sort(GridEntry.DisplayNameComparer); 
                        } 

                        PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[props.Count]; 
                        props.CopyTo(propertyDescriptors, 0);

                        props = new PropertyDescriptorCollection(SortParenProperties(propertyDescriptors));
                    } 

                    if (defProp == null && props.Count > 0) 
                    { 
                        defProp = props[0];
                    } 

                    // if the target object is an array and nothing else has provided a set of
                    // properties to use, then expand the array.
                    // 
                    if ((props == null || props.Count == 0) && objType != null && objType.IsArray && obj != null)
                    { 
 
                        Array objArray = (Array)obj;
 
                        entries = new GridEntry[objArray.Length];

                        for (int i = 0; i < entries.Length; i++)
                        { 
                            entries[i] = new ArrayElementGridEntry(this.ownerGrid, peParent, i);
                        } 
                    } 
                    else
                    { 
                        // otherwise, create the proper GridEntries.
                        //
                        bool createInstanceSupported = TypeConverter.GetCreateInstanceSupported(this);
                        entries = new GridEntry[props.Count]; 
                        int index = 0;
 
                        // loop through all the props we got and create property descriptors. 
                        //
                        foreach (PropertyDescriptor pd in props) 
                        {
                            GridEntry newEntry;

                            // make sure we've got a valid property, otherwise hide it 
                            //
                            bool hide = false; 
                            try 
                            {
                                object owner = obj; 
                                if (obj is ICustomTypeDescriptor)
                                {
                                    owner = ((ICustomTypeDescriptor)obj).GetPropertyOwner(pd);
                                } 
                                pd.GetValue(owner);
                            } 
                            catch (Exception w) 
                            {
                                if (PbrsAssertPropsSwitch.Enabled) 
                                {
                                    Debug.Fail("Bad property '" + peParent.PropertyLabel + "." + pd.Name + "': " + w.ToString());
                                }
                                hide = true; 
                            }
 
                            if (createInstanceSupported) 
                            {
                                newEntry = new ImmutablePropertyDescriptorGridEntry(this.ownerGrid, peParent, pd, hide); 
                            }
                            else
                            {
                                newEntry = new PropertyDescriptorGridEntry(this.ownerGrid, peParent, pd, hide); 
                            }
 
                            if (forceReadOnly) 
                            {
                                newEntry.flags |= FLAG_FORCE_READONLY; 
                            }

                            // check to see if we've come across the default item.
                            // 
                            if (pd.Equals(defProp))
                            { 
                                this.DefaultChild = newEntry; 
                            }
 
                            // add it to the array.
                            //
                            entries[index++] = newEntry;
                        } 
                    }
                } 
            } 
            catch (Exception e)
            { 
#if DEBUG
                if (PbrsAssertPropsSwitch.Enabled) {
                    // Checked builds are not giving us enough information here.  So, output as much stuff as
                    // we can. 
                    System.Text.StringBuilder b = new System.Text.StringBuilder();
                    b.Append(string.Format(CultureInfo.CurrentCulture, "********* Debug log written on {0} ************\r\n", DateTime.Now)); 
                    b.Append(string.Format(CultureInfo.CurrentCulture, "Exception '{0}' reading properties for object {1}.\r\n", e.GetType().Name, obj)); 
                    b.Append(string.Format(CultureInfo.CurrentCulture, "Exception Text: \r\n{0}", e.ToString()));
                    b.Append(string.Format(CultureInfo.CurrentCulture, "Exception stack: \r\n{0}", e.StackTrace)); 
                    string path = string.Format(CultureInfo.CurrentCulture, "{0}\\PropertyGrid.log", Environment.GetEnvironmentVariable("SYSTEMDRIVE"));
                    System.IO.FileStream s = new System.IO.FileStream(path, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.None);
                    System.IO.StreamWriter w = new System.IO.StreamWriter(s);
                    w.Write(b.ToString()); 
                    w.Close();
                    s.Close(); 
                    RTLAwareMessageBox.Show(null, b.ToString(), SR.GetString(SR.PropertyGridInternalNoProp, path), 
                        MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
                } 
#endif
                Debug.Fail("Failed to get properties: " + e.GetType().Name + "," + e.Message + "\n" + e.StackTrace);
            }
            return entries; 
        }
 
        ///  
        /// 
        /// Resets the current item 
        /// 
        public virtual void ResetPropertyValue() {
            NotifyValue(NOTIFY_RESET);
            Refresh(); 
        }
 
        /* 
        /// 
        /// Checks if the value of the current item can be modified by the user. 
        /// 
        /// 
        /// True if the value can be modified
        ///  
        public virtual bool CanSetPropertyValue() {
            return 0 != (Flags & (GridEntry.FLAG_DROPDOWN_EDITABLE | GridEntry.FLAG_TEXT_EDITABLE | GridEntry.FLAG_CUSTOM_EDITABLE | GridEntry.FLAG_ENUMERABLE)); 
        } 
        */
 
        /*
        /// 
        /// Returns if it's an editable item.  An example of a readonly
        /// editable item is a collection property -- the property itself 
        /// can not be modified, but it's value (e.g. it's children) can, so
        /// we don't want to draw it as readonly. 
        ///  
        /// 
        /// True if the value associated with this property (e.g. it's children) can be modified even if it's readonly. 
        /// 
        public virtual bool CanSetReadOnlyPropertyValue() {
            return GetFlagSet(GridEntry.FLAG_READONLY_EDITABLE);
        } 
        */
 
        ///  
        /// 
        /// Returns if the property can be reset 
        /// 
        public virtual bool CanResetPropertyValue() {
            return NotifyValue(NOTIFY_CAN_RESET);
        } 

        ///  
        ///  
        /// Called when the item is double clicked.
        ///  
        public virtual bool DoubleClickPropertyValue() {
            return NotifyValue(NOTIFY_DBL_CLICK);
        }
 

        ///  
        ///  
        /// Returns the text value of this property.
        ///  
        public virtual string GetPropertyTextValue() {
            return GetPropertyTextValue(this.PropertyValue);
        }
 
        /// 
        ///  
        /// Returns the text value of this property. 
        /// 
        public virtual string GetPropertyTextValue(object value) { 
            string str = null;

            TypeConverter converter = TypeConverter;
            try 
            {
                str = converter.ConvertToString(this, value); 
            } 
            catch (Exception t)
            { 
                Debug.Fail("Bad Type Converter! " + t.GetType().Name + ", " + t.Message + "," + converter.ToString(), t.ToString());
            }

            if (str == null) { 
                str = String.Empty;
            } 
            return str; 
        }
 
        /// 
        /// 
        /// Returns the text values of this property.
        ///  
        public virtual object[] GetPropertyValueList() {
            ICollection values = TypeConverter.GetStandardValues(this); 
            if (values != null) { 
                object[] valueArray = new object[values.Count];
                values.CopyTo(valueArray, 0); 
                return valueArray;
            }
            return new object[0];
        } 

        public override int GetHashCode() { 
            // These can be null, so workaround giving hashcode = 0 for null objects. 
            object label = this.PropertyLabel;
            object type = this.PropertyType; 
            UInt32 h1 = (UInt32)((label == null)  ? 0 : label.GetHashCode());
            UInt32 h2 = (UInt32)((type == null)   ? 0 : type.GetHashCode());
            UInt32 h3 = (UInt32)GetType().GetHashCode();
 
            return(int)(h1 ^ ((h2 << 13) | (h2 >> 19)) ^ ((h3 << 26) | (h3 >> 6)));
        } 
 
        /// 
        ///  
        /// Checks if a given flag is set
        /// 
        protected virtual bool GetFlagSet(int flag) {
            return((flag & Flags) != 0); 
        }
 
        protected Font GetFont(bool boldFont) { 
            if (boldFont)
                return GridEntryHost.GetBoldFont(); 
            else
                return GridEntryHost.GetBaseFont();
        }
 
        protected IntPtr GetHfont(bool boldFont) {
            if (boldFont) 
                return GridEntryHost.GetBoldHfont(); 
            else
                return GridEntryHost.GetBaseHfont(); 
        }

        /// 
        ///  
        ///      Retrieves the requested service.  This may
        ///      return null if the requested service is not 
        ///      available. 
        /// 
        public virtual object GetService(Type serviceType) { 

            if (serviceType == typeof(GridItem)) {
                return (GridItem)this;
            } 

            if (parentPE != null) { 
                return parentPE.GetService(serviceType); 
            }
            return null; 
        }

        internal virtual bool NonParentEquals(object obj) {
            if (obj == this) return true; 
            if (obj == null) return false;
            if (!(obj is GridEntry)) return false; 
            GridEntry pe = (GridEntry)obj; 

            return pe.PropertyLabel.Equals(this.PropertyLabel) && 
                   pe.PropertyType.Equals(this.PropertyType) && pe.PropertyDepth == this.PropertyDepth;
        }

 
        /// 
        ///  
        /// Paints the label portion of this GridEntry into the given Graphics object.  This 
        /// is called by the GridEntry host (the PropertyGridView) when this GridEntry is
        /// to be painted. 
        /// 
        public virtual void PaintLabel(System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, bool selected, bool paintFullLabel) {
            PropertyGridView gridHost = this.GridEntryHost;
            Debug.Assert(gridHost != null, "No propEntryHost"); 
            string strLabel = this.PropertyLabel;
 
            int borderWidth = gridHost.GetOutlineIconSize()+OUTLINE_ICON_PADDING; 

            // fill the background if necessary 
            Brush bkBrush = selected ? SystemBrushes.Highlight : this.GetBackgroundBrush(g);
            // if we don't have focus, paint with the line color
            if (selected && !hasFocus) {
                bkBrush = gridHost.GetLineBrush(g); 
            }
 
            bool fBold = ((this.Flags & GridEntry.FLAG_LABEL_BOLD) != 0); 
            Font font = GetFont(fBold);
 
            int labelWidth = GetLabelTextWidth(strLabel, g, font);

            int neededWidth = paintFullLabel ? labelWidth : 0;
            int stringX = rect.X + this.PropertyLabelIndent; 
            Brush blank = bkBrush;
 
            if (paintFullLabel && (neededWidth >= (rect.Width-(stringX+2)))) { 
                int totalWidth = stringX + neededWidth + PropertyGridView.GDIPLUS_SPACE; // 5 = extra needed to ensure text draws completely and isn't clipped.
#if PBRS_PAINT_DEBUG 
                blank = Brushes.Green;
#endif

                // blank out the space we're going to use 
                g.FillRectangle(blank, borderWidth-1, rect.Y, totalWidth-borderWidth+3, rect.Height);
 
                // draw an end line 
                Pen linePen = new Pen(gridHost.GetLineColor());
                g.DrawLine(linePen, totalWidth, rect.Y, totalWidth, rect.Height); 
                linePen.Dispose();

                // set the new width that we can draw into
                rect.Width = totalWidth - rect.X; 
            }
            else { // Normal case -- no pseudo-tooltip for the label 
 
#if PBRS_PAINT_DEBUG
                blank = Brushes.Red; 
#endif
                // Debug.WriteLine(rect.X.ToString() +" "+ rect.Y.ToString() +" "+ rect.Width.ToString() +" "+ rect.Height.ToString());
                g.FillRectangle(blank, rect.X, rect.Y, rect.Width, rect.Height);
            } 

            // draw the border stripe on the left 
            Brush stripeBrush = gridHost.GetLineBrush(g); 
            g.FillRectangle(stripeBrush, rect.X, rect.Y, borderWidth, rect.Height);
 
            if (selected && hasFocus) {
                g.FillRectangle(SystemBrushes.Highlight, stringX, rect.Y, rect.Width-stringX-1, rect.Height);
            }
 
            int maxSpace = Math.Min(rect.Width-stringX-1, labelWidth + PropertyGridView.GDIPLUS_SPACE);
            Rectangle textRect = new Rectangle(stringX, rect.Y + 1, maxSpace, rect.Height - 1); 
 

            if (!Rectangle.Intersect(textRect, clipRect).IsEmpty)  { 
                Region oldClip = g.Clip;
                g.SetClip(textRect);

                // Do actual drawing 
                // A brush is needed if using GDI+ only (UseCompatibleTextRendering); if using GDI, only the color is needed.
                Color textColor = (selected && hasFocus) ? SystemColors.HighlightText : g.GetNearestColor(this.LabelTextColor); 
 
                if( this.ownerGrid.UseCompatibleTextRendering ) {
                    using( Brush textBrush = new SolidBrush(textColor)){ 
                        StringFormat stringFormat = new StringFormat(StringFormatFlags.NoWrap);
                        stringFormat.Trimming = StringTrimming.None;
                        g.DrawString(strLabel, font, textBrush, textRect, stringFormat);
                    } 
                }
                else{ 
                    TextRenderer.DrawText( g, strLabel, font, textRect, textColor, PropertyGrid.MeasureTextHelper.GetTextRendererFlags() ); 
                }
    #if PBRS_PAINT_DEBUG 
                textRect.Width --;
                textRect.Height--;
                g.DrawRectangle(new Pen(Color.Blue), textRect);
    #endif 
                g.SetClip(oldClip, CombineMode.Replace);
                oldClip.Dispose();   // clip is actually copied out. 
 
                if (maxSpace <= labelWidth) {
                    this.labelTipPoint = new Point(stringX+2, rect.Y+1); 
                }
                else {
                    this.labelTipPoint = InvalidPoint;
                } 
            }
 
            rect.Y -= 1; 
            rect.Height += 2;
 
            PaintOutline(g, rect);
        }

        ///  
        /// 
        /// Paints the outline portion of this GridEntry into the given Graphics object.  This 
        /// is called by the GridEntry host (the PropertyGridView) when this GridEntry is 
        /// to be painted.
        ///  
        public virtual void PaintOutline(System.Drawing.Graphics g, Rectangle r) {
            // draw outline box.
            if (this.Expandable) {
                bool fExpanded = this.InternalExpanded; 
                Rectangle outline = this.OutlineRect;
 
                // make sure we're in our bounds 
                outline = Rectangle.Intersect(r, outline);
                if (outline.IsEmpty) return; 

                // draw border area box
                Brush b = this.GetBackgroundBrush(g);
                Pen p; 
                Color penColor = GridEntryHost.GetTextColor();
                if (penColor.IsSystemColor) { 
                    p = SystemPens.FromSystemColor(penColor); 
                }
                else { 
                    p = new Pen(penColor);
                }

                g.FillRectangle(b, outline); 
                g.DrawRectangle(p, outline.X, outline.Y, outline.Width - 1, outline.Height - 1);
 
                // draw horizontal line for +/- 
                int indent = 2;
                g.DrawLine(p, outline.X + indent,outline.Y + outline.Height / 2, 
                           outline.X + outline.Width - indent - 1,outline.Y + outline.Height/2);

                // draw vertical line to make a +
                if (!fExpanded) { 
                    g.DrawLine(p, outline.X + outline.Width/2, outline.Y + indent,
                               outline.X + outline.Width/2, outline.Y + outline.Height - indent - 1); 
                } 

                if (!penColor.IsSystemColor) { 
                    p.Dispose();
                }
            }
        } 

        ///  
        ///  
        /// Paints the value portion of this GridEntry into the given Graphics object.  This
        /// is called by the GridEntry host (the PropertyGridView) when this GridEntry is 
        /// to be painted.
        /// 
        public virtual void PaintValue(object val, System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, PaintValueFlags paintFlags) {
            PropertyGridView gridHost = this.GridEntryHost; 
            Debug.Assert(gridHost != null, "No propEntryHost");
            int cPaint = 0; 
 
            Color textColor = gridHost.GetTextColor();
            if (this.ShouldRenderReadOnly) { 
                textColor = GridEntryHost.GrayTextColor;
            }

            string strValue; 

            if ((paintFlags & PaintValueFlags.FetchValue) != PaintValueFlags.None) { 
               if (cacheItems != null && cacheItems.useValueString) { 
                  strValue = cacheItems.lastValueString;
                  val = cacheItems.lastValue; 
               }
               else {
                  val = this.PropertyValue;
                  strValue = GetPropertyTextValue(val); 
                  if (cacheItems == null) {
                     cacheItems = new CacheItems(); 
                  } 
                  cacheItems.lastValueString = strValue;
                  cacheItems.useValueString = true; 
                  cacheItems.lastValueTextWidth = -1;
                  cacheItems.lastValueFont = null;
                  cacheItems.lastValue = val;
               } 
            }
            else { 
               strValue = GetPropertyTextValue(val); 
            }
 
            // paint out the main rect using the default brush
            //            Brush bkBrush = selected ? SystemBrushes.Highlight : this.BackgroundBrush;
            Brush bkBrush = this.GetBackgroundBrush(g);
            Debug.Assert(bkBrush != null, "We didn't find a good background brush for PaintValue"); 

            if ((paintFlags & PaintValueFlags.DrawSelected) != PaintValueFlags.None) { 
                bkBrush = System.Drawing.SystemBrushes.Highlight; 
                textColor = SystemColors.HighlightText;
            } 

            Brush blank = bkBrush;
#if PBRS_PAINT_DEBUG
            blank = Brushes.Yellow; 
#endif
            //g.FillRectangle(blank, rect.X-1, rect.Y, rect.Width+1, rect.Height); 
            g.FillRectangle(blank, clipRect); 

            if (IsCustomPaint) { 
                cPaint = gridHost.GetValuePaintIndent();
                Rectangle rectPaint = new Rectangle(rect.X + 1, rect.Y + 1, gridHost.GetValuePaintWidth(), gridHost.GetGridEntryHeight() - 2);

                if (!Rectangle.Intersect(rectPaint, clipRect).IsEmpty) { 
                   UITypeEditor uie = UITypeEditor;
                   if (uie != null) { 
                       uie.PaintValue(new PaintValueEventArgs(this, val, g, rectPaint)); 
                   }
 
                   // paint a border around the area
                   rectPaint.Width --;
                   rectPaint.Height--;
                   g.DrawRectangle(SystemPens.WindowText, rectPaint); 
                }
            } 
 
            rect.X += cPaint + gridHost.GetValueStringIndent();
            rect.Width -= cPaint + 2 * gridHost.GetValueStringIndent(); 

            // bold the property if we need to persist it (e.g. it's not the default value)
            bool valueModified = ((paintFlags & PaintValueFlags.CheckShouldSerialize) != PaintValueFlags.None) && ShouldSerializePropertyValue();
 

            if (strValue != null && strValue.Length > 0) { 
 
                Font f = GetFont(valueModified);
 
                if (strValue.Length > maximumLengthOfPropertyString)
                {
                    strValue = strValue.Substring(0, maximumLengthOfPropertyString);
                } 
                int textWidth = GetValueTextWidth(strValue, g, f);
                bool doToolTip = false; 
 
                //subhag (66503) To check if text contains multiple lines
                // 
                if (textWidth >= rect.Width ||  GetMultipleLines(strValue))
                     doToolTip = true;

                if (Rectangle.Intersect(rect, clipRect).IsEmpty) { 
                     return;
                } 
 
                // Do actual drawing
 
                //strValue = ReplaceCRLF(strValue);


                 // AS/URT  55015 
                // bump the text down 2 pixels and over 1 pixel.
                if ((paintFlags & PaintValueFlags.PaintInPlace) != PaintValueFlags.None) { 
                    rect.Offset(1, 2); 
                }
                else { 
                    // only go down one pixel when we're painting in the listbox
                    rect.Offset(1, 1);
                }
 
                Matrix m = g.Transform;
                IntPtr hdc = g.GetHdc(); 
                IntNativeMethods.RECT lpRect = IntNativeMethods.RECT.FromXYWH(rect.X + (int)m.OffsetX + 2, rect.Y + (int)m.OffsetY - 1, rect.Width - 4, rect.Height); 
                IntPtr hfont = GetHfont(valueModified);
 
                int oldTextColor = 0;
                int oldBkColor = 0;

                Color bkColor = ((paintFlags & PaintValueFlags.DrawSelected) != PaintValueFlags.None) ? SystemColors.Highlight : GridEntryHost.BackColor; 

                try { 
                    oldTextColor = SafeNativeMethods.SetTextColor(new HandleRef(g, hdc), SafeNativeMethods.RGBToCOLORREF(textColor.ToArgb())); 
                    oldBkColor = SafeNativeMethods.SetBkColor(new HandleRef(g, hdc), SafeNativeMethods.RGBToCOLORREF(bkColor.ToArgb()));
                    hfont = SafeNativeMethods.SelectObject(new HandleRef(g, hdc), new HandleRef(null, hfont)); 
                    int format = IntNativeMethods.DT_EDITCONTROL | IntNativeMethods.DT_EXPANDTABS | IntNativeMethods.DT_NOCLIP | IntNativeMethods.DT_SINGLELINE | IntNativeMethods.DT_NOPREFIX;
                    if (gridHost.DrawValuesRightToLeft) {
                        format |= IntNativeMethods.DT_RIGHT | IntNativeMethods.DT_RTLREADING;
                    } 

                    // For password mode, Replace the string value either with * or a bullet, depending on the OS platform 
                    if (ShouldRenderPassword) { 

                        if (passwordReplaceChar == (char)0) { 
                            if (Environment.OSVersion.Version.Major > 4) {
                                passwordReplaceChar = (char)0x25CF; // Bullet is 2022, but edit box uses round circle 25CF
                            }
                            else { 
                                passwordReplaceChar = '*';
                            } 
                        } 

                        strValue = new string(passwordReplaceChar, strValue.Length); 
                    }

                    IntUnsafeNativeMethods.DrawText(new HandleRef(g, hdc), strValue, ref lpRect, format);
                } 
                finally {
                    SafeNativeMethods.SetTextColor(new HandleRef(g, hdc), oldTextColor); 
                    SafeNativeMethods.SetBkColor(new HandleRef(g, hdc), oldBkColor); 
                    hfont = SafeNativeMethods.SelectObject(new HandleRef(g, hdc), new HandleRef(null, hfont));
                    g.ReleaseHdcInternal(hdc); 
                }


                #if PBRS_PAINT_DEBUG 
                    rect.Width --;
                    rect.Height--; 
                    g.DrawRectangle(new Pen(Color.Purple), rect); 
               #endif
 
                if (doToolTip) {
                    this.ValueToolTipLocation = new Point(rect.X+2, rect.Y-1);
                }
                else { 
                     this.ValueToolTipLocation = InvalidPoint;
                } 
            } 

            return; 
        }

        public virtual bool OnComponentChanging() {
            if (ComponentChangeService != null) { 
                try {
                    ComponentChangeService.OnComponentChanging(GetValueOwner(), PropertyDescriptor); 
                } 
                catch (CheckoutException coEx) {
                    if (coEx == CheckoutException.Canceled) { 
                        return false;
                    }
                    throw coEx;
                } 
            }
            return true; 
        } 

        public virtual void OnComponentChanged() { 
            if (ComponentChangeService != null) {
                ComponentChangeService.OnComponentChanged(GetValueOwner(), PropertyDescriptor, null, null);
            }
        } 

        ///  
        ///  
        /// Called when the label portion of this GridEntry is clicked.
        /// Default implmentation fired the event to any listeners, so be sure 
        /// to call base.OnLabelClick(e) if this is overrideen.
        /// 
        protected virtual void OnLabelClick(EventArgs e) {
            RaiseEvent(EVENT_LABEL_CLICK, e); 
        }
 
        ///  
        /// 
        /// Called when the label portion of this GridEntry is double-clicked. 
        /// Default implmentation fired the event to any listeners, so be sure
        /// to call base.OnLabelDoubleClick(e) if this is overrideen.
        /// 
        protected virtual void         OnLabelDoubleClick(EventArgs e) { 
            RaiseEvent(EVENT_LABEL_DBLCLICK, e);
        } 
 
        /// 
        ///  
        /// Called when the GridEntry is clicked.
        /// 
        public virtual bool OnMouseClick(int x, int y, int count, MouseButtons button) {
            // where are we at? 
            PropertyGridView gridHost = this.GridEntryHost;
            Debug.Assert(gridHost != null, "No prop entry host!"); 
 
            // make sure it's the left button
            if ((button & MouseButtons.Left) != MouseButtons.Left) { 
                return false;
            }

 
            int labelWidth  = gridHost.GetLabelWidth();
 
            // are we in the label? 
            if (x >= 0 && x <= labelWidth) {
 
                // are we on the outline?
                if (Expandable) {
                    Rectangle outlineRect = OutlineRect;
                    if (outlineRect.Contains(x, y)) { 
                        if (count % 2 == 0) {
                            OnOutlineDoubleClick(EventArgs.Empty); 
                        } 
                        else {
                            OnOutlineClick(EventArgs.Empty); 
                        }
                        return true;
                    }
                } 

                if (count % 2 == 0) { 
                    OnLabelDoubleClick(EventArgs.Empty); 
                }
                else { 
                    OnLabelClick(EventArgs.Empty);
                }
                return true;
            } 

            // are we in the value? 
            labelWidth += gridHost.GetSplitterWidth(); 
            if (x >= labelWidth  && x <= labelWidth + gridHost.GetValueWidth()) {
                if (count % 2 == 0) { 
                    OnValueDoubleClick(EventArgs.Empty);
                }
                else {
                    OnValueClick(EventArgs.Empty); 
                }
                return true; 
            } 
            return false;
        } 

        /// 
        /// 
        /// Called when the outline icon portion of this GridEntry is clicked. 
        /// Default implmentation fired the event to any listeners, so be sure
        /// to call base.OnOutlineClick(e) if this is overrideen. 
        ///  
        protected virtual void OnOutlineClick(EventArgs e) {
            RaiseEvent(EVENT_OUTLINE_CLICK, e); 
        }

        /// 
        ///  
        /// Called when the outline icon portion of this GridEntry is double-clicked.
        /// Default implmentation fired the event to any listeners, so be sure 
        /// to call base.OnOutlineDoubleClick(e) if this is overrideen. 
        /// 
        protected virtual void OnOutlineDoubleClick(EventArgs e) { 
            RaiseEvent(EVENT_OUTLINE_DBLCLICK, e);
        }

        ///  
        /// 
        /// Called when RecreateChildren is called. 
        /// Default implmentation fired the event to any listeners, so be sure 
        /// to call base.OnOutlineDoubleClick(e) if this is overrideen.
        ///  
        protected virtual void OnRecreateChildren(GridEntryRecreateChildrenEventArgs e) {
            Delegate handler = GetEventHandler(EVENT_RECREATE_CHILDREN);
            if (handler != null) ((GridEntryRecreateChildrenEventHandler)handler)(this, e);
        } 

        ///  
        ///  
        /// Called when the value portion of this GridEntry is clicked.
        /// Default implmentation fired the event to any listeners, so be sure 
        /// to call base.OnValueClick(e) if this is overrideen.
        /// 
        protected virtual void OnValueClick(EventArgs e) {
            RaiseEvent(EVENT_VALUE_CLICK, e); 
        }
 
        ///  
        /// 
        /// Called when the value portion of this GridEntry is clicked. 
        /// Default implmentation fired the event to any listeners, so be sure
        /// to call base.OnValueDoubleClick(e) if this is overrideen.
        /// 
        protected virtual void OnValueDoubleClick(EventArgs e) { 
            RaiseEvent(EVENT_VALUE_DBLCLICK, e);
        } 
 

 
        internal bool OnValueReturnKey() {
            return NotifyValue(NOTIFY_RETURN);
        }
 
        /// 
        ///  
        /// Sets the specified flag 
        /// 
        protected virtual void SetFlag(int flag, bool fVal) { 
            SetFlag(flag, (fVal ? flag : 0));
        }

        ///  
        /// 
        /// Sets the default child of this entry, given a valid value mask. 
        ///  
        protected virtual void SetFlag(int flag_valid, int flag, bool fVal) {
            SetFlag(flag_valid | flag, 
                    flag_valid | (fVal ? flag : 0));
        }

        ///  
        /// 
        /// Sets the value of a flag 
        ///  
        protected virtual void SetFlag(int flag, int val) {
            Flags = (Flags & ~(flag)) | val; 
        }

        public override bool Select() {
            if (Disposed) { 
                return false;
            } 
 
            try {
                GridEntryHost.SelectedGridEntry = this; 
                return true;
            }
            catch {
            } 
            return false;
        } 
 
        /// 
        ///  
        /// Checks if this value should be persisited.
        /// 
        internal virtual bool ShouldSerializePropertyValue() {
 
            if (cacheItems != null) {
                if (cacheItems.useShouldSerialize) { 
                     return cacheItems.lastShouldSerialize; 
                }
                else { 
                    cacheItems.lastShouldSerialize = NotifyValue(NOTIFY_SHOULD_PERSIST);
                    cacheItems.useShouldSerialize = true;
                }
            } 
            else {
               cacheItems = new CacheItems(); 
               cacheItems.lastShouldSerialize = NotifyValue(NOTIFY_SHOULD_PERSIST); 
               cacheItems.useShouldSerialize = true;
            } 
            return cacheItems.lastShouldSerialize;
        }

        private PropertyDescriptor[] SortParenProperties(PropertyDescriptor[] props) { 

            PropertyDescriptor[] newProps = null; 
            int newPos = 0; 

 
            // first scan the list and move any parentesized properties to the front.
            for (int i = 0; i < props.Length; i++) {
                if (((ParenthesizePropertyNameAttribute)props[i].Attributes[typeof(ParenthesizePropertyNameAttribute)]).NeedParenthesis) {
                    if (newProps == null) { 
                        newProps = new PropertyDescriptor[props.Length];
                    } 
                    newProps[newPos++] = props[i]; 
                    props[i] = null;
                } 
            }


            // second pass, copy any that didn't have the parens. 
            if (newPos > 0) {
                for (int i = 0; i < props.Length; i++) { 
                    if (props[i] != null) { 
                        newProps[newPos++] = props[i];
                    } 
                }
                props = newProps;
            }
            return props; 
        }
 
        ///  
        /// 
        /// Sends a notify message to this GridEntry, and returns the success result 
        /// 
        internal virtual bool NotifyValueGivenParent(object obj, int type) {
            return false;
        } 

        ///  
        ///  
        /// Sends a notify message to the child GridEntry, and returns the success result
        ///  
        internal virtual bool NotifyChildValue(GridEntry pe, int type) {

            return pe.NotifyValueGivenParent(pe.GetValueOwner(),type);
        } 

        internal virtual bool NotifyValue(int type) { 
            // KILLME, [....], more spagetti 
            if (parentPE == null) {
                return true; 
            }
            else {
                return parentPE.NotifyChildValue(this, type);
            } 
        }
 
        internal void RecreateChildren() { 
            RecreateChildren(-1);
        } 

        internal void RecreateChildren(int oldCount) {

            // cause the flags to be rebuilt as well... 
            bool wasExpanded = this.InternalExpanded || oldCount > 0;
 
            if (oldCount == -1) { 
                oldCount = this.VisibleChildCount;
            } 

            ResetState();
            if (oldCount == 0) {
                return; 
            }
 
            foreach(GridEntry child in ChildCollection) { 
                child.RecreateChildren();
            } 

            DisposeChildren();
            this.InternalExpanded = wasExpanded;
            OnRecreateChildren(new GridEntryRecreateChildrenEventArgs(oldCount, VisibleChildCount)); 
        }
 
        ///  
        /// 
        /// Refresh the current GridEntry's value and it's children 
        /// 
        public virtual void Refresh() {

            Type type = this.PropertyType; 
            if (type != null && type.IsArray) {
                CreateChildren(true); 
            } 

            if (this.childCollection != null) { 

                // check to see if the value has changed.
                //
                if (this.InternalExpanded && cacheItems != null && cacheItems.lastValue != null && cacheItems.lastValue != this.PropertyValue) { 
                    ClearCachedValues();
                    RecreateChildren(); 
                    return; 
                }
                else if (this.InternalExpanded) { 
                    // otherwise just do a refresh.
                    IEnumerator childEnum = childCollection.GetEnumerator();
                    while (childEnum.MoveNext()) {
                        object o = childEnum.Current; 
                        Debug.Assert(o != null, "Collection contains a null element.  But how? Garbage collector hole?  GDI+ corrupting memory?");
                        GridEntry e = (GridEntry) o; 
                        e.Refresh(); 
                    }
                } 
                else {
                    DisposeChildren();
                }
            } 

            ClearCachedValues(); 
        } 

        public virtual void         RemoveOnLabelClick(EventHandler h) { 
            RemoveEventHandler(EVENT_LABEL_CLICK, h);
        }
        public virtual void         RemoveOnLabelDoubleClick(EventHandler h) {
            RemoveEventHandler(EVENT_LABEL_DBLCLICK, h); 
        }
 
        public virtual void         RemoveOnValueClick(EventHandler h) { 
            RemoveEventHandler(EVENT_VALUE_CLICK, h);
        } 

        public virtual void         RemoveOnValueDoubleClick(EventHandler h) {
            RemoveEventHandler(EVENT_VALUE_DBLCLICK, h);
        } 

        public virtual void         RemoveOnOutlineClick(EventHandler h) { 
            RemoveEventHandler(EVENT_OUTLINE_CLICK, h); 
        }
 
        public virtual void         RemoveOnOutlineDoubleClick(EventHandler h) {
            RemoveEventHandler(EVENT_OUTLINE_DBLCLICK, h);
        }
 
        public virtual void         RemoveOnRecreateChildren(GridEntryRecreateChildrenEventHandler h) {
            RemoveEventHandler(EVENT_RECREATE_CHILDREN, h); 
        } 

        /* 
        private string ReplaceCRLF(string str) {
            str = str.Replace('\r', (char)1);
            str = str.Replace('\n', (char)1);
            return str; 
        }
        */ 
 
        protected void ResetState() {
            this.Flags = 0; 
            ClearCachedValues();
        }

        ///  
        /// 
        /// Sets the value of this GridEntry from text 
        ///  
        public virtual bool SetPropertyTextValue(string str) {
            bool fChildrenPrior = (childCollection != null && childCollection.Count > 0); 
            this.PropertyValue = ConvertTextToValue(str);
            CreateChildren();
            bool fChildrenAfter = (childCollection != null && childCollection.Count > 0);
            return(fChildrenPrior != fChildrenAfter); 
        }
 
        public override string ToString() { 
            return GetType().FullName + " " + this.PropertyLabel;
        } 



#if !DONT_SUPPORT_ADD_EVENT_HANDLER 
        private EventEntry eventList;
 
        protected virtual void AddEventHandler(object key, Delegate handler) { 
            // Locking 'this' here is ok since this is an internal class.  See VSW#464499.
            lock(this) { 
                if (handler == null) return;
                for (EventEntry e = eventList; e != null; e = e.next) {
                    if (e.key == key) {
                        e.handler = Delegate.Combine(e.handler, handler); 
                        return;
                    } 
                } 
                eventList = new EventEntry(eventList, key, handler);
            } 
        }

        protected virtual void RaiseEvent(object key, EventArgs e) {
            Delegate handler = GetEventHandler(key); 
            if (handler != null) ((EventHandler)handler)(this, e);
        } 
 
        protected virtual Delegate GetEventHandler(object key) {
            // Locking 'this' here is ok since this is an internal class.  See VSW#464499. 
            lock(this) {
                for (EventEntry e = eventList; e != null; e = e.next) {
                    if (e.key == key) return e.handler;
                } 
                return null;
            } 
        } 

        protected virtual void RemoveEventHandler(object key, Delegate handler) { 
            // Locking this here is ok since this is an internal class.  See VSW#464499.
            lock(this) {
                if (handler == null) return;
                for (EventEntry e = eventList, prev = null; e != null; prev = e, e = e.next) { 
                    if (e.key == key) {
                        e.handler = Delegate.Remove(e.handler, handler); 
                        if (e.handler == null) { 
                            if (prev == null) {
                                eventList = e.next; 
                            }
                            else {
                                prev.next = e.next;
                            } 
                        }
                        return; 
                    } 
                }
            } 
        }

        protected virtual void RemoveEventHandlers() {
            eventList = null; 
        }
 
        ///  
        /// 
        ///  
        private sealed class EventEntry {
            internal EventEntry next;
            internal object key;
            internal Delegate handler; 

            internal EventEntry(EventEntry next, object key, Delegate handler) { 
                this.next = next; 
                this.key = key;
                this.handler = handler; 
            }
        }
#endif
 
        [ComVisible(true)]
        public class GridEntryAccessibleObject : AccessibleObject { 
 
            GridEntry owner = null;
            private delegate void SelectDelegate(AccessibleSelection flags); 

            public GridEntryAccessibleObject(GridEntry owner) : base() {
                Debug.Assert(owner != null, "GridEntryAccessibleObject must have a valid owner GridEntry");
                this.owner = owner; 
            }
 
            public override Rectangle Bounds { 
                get {
                    return PropertyGridView.AccessibilityGetGridEntryBounds(owner); 
                }
            }

            public override string DefaultAction { 
                get {
                    if (!owner.Expandable) { 
                        return base.DefaultAction; 
                    }
                    else if (owner.Expanded) { 
                        return SR.GetString(SR.AccessibleActionCollapse);
                    }
                    else {
                        return SR.GetString(SR.AccessibleActionExpand); 
                    }
                } 
            } 

            public override string Description { 
                get {
                    return owner.PropertyDescription;
                }
            } 

            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            public override void DoDefaultAction() { 
                owner.OnOutlineClick(EventArgs.Empty);
            } 

            public override string Name {
                get {
                    return owner.PropertyLabel; 
                }
            } 
 
            public override AccessibleObject Parent {
                [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
                get {
                    return((Control)this.owner.GridEntryHost).AccessibilityObject;
                }
            } 

            private PropertyGridView PropertyGridView { 
                get { 
                    return(PropertyGridView)((PropertyGridView.PropertyGridViewAccessibleObject)Parent).Owner;
                } 
            }

            public override AccessibleRole Role {
                get { 
                    return AccessibleRole.Row;
                } 
            } 

            public override AccessibleStates State { 
                get {
                    AccessibleStates state = AccessibleStates.Selectable | AccessibleStates.Focusable;

                    // Determine focus 
                    //
                    if (owner.Focus) { 
                        state |= AccessibleStates.Focused; 
                    }
 
                    // Determine selected
                    //
                    Debug.Assert(Parent != null, "GridEntry AO does not have a parent AO");
                    PropertyGridView.PropertyGridViewAccessibleObject parent = (PropertyGridView.PropertyGridViewAccessibleObject)Parent; 
                    if (parent.GetSelected() == this) {
                        state |= AccessibleStates.Selected; 
                    } 

                    // Determine expanded/collapsed state 
                    //
                    if (owner.Expandable) {
                        if (owner.Expanded) {
                            state |= AccessibleStates.Expanded; 
                        }
                        else { 
                            state |= AccessibleStates.Collapsed; 
                        }
                    } 

                    // Determine readonly/editable state
                    //
                    if (owner.ShouldRenderReadOnly) { 
                        state |= AccessibleStates.ReadOnly;
                    } 
 
                    // Determine password state
                    // 
                    if (owner.ShouldRenderPassword) {
                        state |= AccessibleStates.Protected;
                    }
 
                    return state;
                } 
            } 

            public override string Value { 
                [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
                get {
                    return owner.GetPropertyTextValue();
                } 

                [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
                set { 
                    owner.SetPropertyTextValue(value);
                } 
            }

            /// 
            ///  
            ///      Returns the currently focused child, if any.
            ///      Returns this if the object itself is focused. 
            ///  
            public override AccessibleObject GetFocused() {
 
                if (owner.Focus) {
                    return this;
                }
                else { 
                    return null;
                } 
            } 

 
            /// 
            /// 
            ///      Navigate to the next or previous grid entry.
            ///  
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public override AccessibleObject Navigate(AccessibleNavigation navdir) { 
 
                PropertyGridView.PropertyGridViewAccessibleObject parent =
                (PropertyGridView.PropertyGridViewAccessibleObject)Parent; 

                switch (navdir) {
                    case AccessibleNavigation.Down:
                    case AccessibleNavigation.Right: 
                    case AccessibleNavigation.Next:
                        return parent.Next(this.owner); 
 
                    case AccessibleNavigation.Up:
                    case AccessibleNavigation.Left: 
                    case AccessibleNavigation.Previous:
                        return parent.Previous(this.owner);

                    case AccessibleNavigation.FirstChild: 
                    case AccessibleNavigation.LastChild:
                        // Fall through and return null, 
                        // as this object has no children. 
                        break;
                } 

                return null;

            } 

            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            public override void Select(AccessibleSelection flags) { 

                // vs  77963 -- make sure we're on the right thread. 
                //
                if (PropertyGridView.InvokeRequired) {
                    PropertyGridView.Invoke(new SelectDelegate(this.Select), new object[]{flags});
                    return; 
                }
 
                // Focus the PropertyGridView window 
                //
                if ( (flags & AccessibleSelection.TakeFocus) == AccessibleSelection.TakeFocus) { 
                    bool focused = PropertyGridView.FocusInternal();
                }

                // Select the grid entry 
                //
                if ( (flags & AccessibleSelection.TakeSelection) == AccessibleSelection.TakeSelection) { 
                    PropertyGridView.AccessibilitySelect(this.owner); 
                }
            } 

        }

        public class DisplayNameSortComparer : IComparer { 
            public int Compare(object left, object right) {
 		// review: ([....]) Is CurrentCulture correct here?  This was already reviewed as invariant... 
                return String.Compare(((PropertyDescriptor)left).DisplayName, ((PropertyDescriptor)right).DisplayName, true, CultureInfo.CurrentCulture); 
            }
        } 
    }

    internal class AttributeTypeSorter : IComparer{
 
        private static IDictionary typeIds;
 
        private static string GetTypeIdString(Attribute a) { 

            string result; 
            object typeId = a.TypeId;


            if (typeId == null) { 
                Debug.Fail("Attribute '" + a.GetType().FullName + "' does not have a typeid.");
                return ""; 
            } 

            if (typeIds == null) { 
                typeIds = new Hashtable();
                result = null;
            }
            else { 
                result = typeIds[typeId] as string;
            } 
 
            if (result == null) {
                result = typeId.ToString(); 
                typeIds[typeId] = result;
            }
            return result;
        } 

        public int Compare(object obj1, object obj2) { 
            Attribute a1 = obj1 as Attribute; 
            Attribute a2 = obj2 as Attribute;
 
            if (a1 == null && a2 == null) {
                return 0;
            }
            else if (a1 == null) { 
                return -1;
            } 
            else if (a2 == null) { 
                return 1;
            } 
            return String.Compare(AttributeTypeSorter.GetTypeIdString(a1), AttributeTypeSorter.GetTypeIdString(a2), false, CultureInfo.InvariantCulture);
        }
    }
 
    internal delegate void GridEntryRecreateChildrenEventHandler(object sender, GridEntryRecreateChildrenEventArgs rce);
 
    internal class GridEntryRecreateChildrenEventArgs : EventArgs { 
        public readonly int OldChildCount;
        public readonly int NewChildCount; 

        public GridEntryRecreateChildrenEventArgs(int oldCount, int newCount) {
            this.OldChildCount = oldCount;
            this.NewChildCount = newCount; 
        }
    } 
 
}

// 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