File: winforms\Managed\System\WinForms\PropertyGrid.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="PropertyGrid.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms {
 
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Windows.Forms.ComponentModel.Com2Interop;
    using System.Windows.Forms.Design;
    using System.Windows.Forms.PropertyGridInternal;
    using Microsoft.Win32;
 
    /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid"]/*' />
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    [Designer("System.Windows.Forms.Design.PropertyGridDesigner, " + AssemblyRef.SystemDesign)]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
    [SRDescription(SR.DescriptionPropertyGrid)]
    public class PropertyGrid : ContainerControl, IComPropertyBrowser, UnsafeNativeMethods.IPropertyNotifySink {
 
        private DocComment                          doccomment;
        private int                                 dcSizeRatio = -1;
        private int                                 hcSizeRatio = -1;
        private HotCommands                         hotcommands;
        private ToolStrip                           toolStrip;
        
        private bool                                helpVisible = true;
        private bool                                toolbarVisible = true;
 
        private ImageList[]                         imageList = new ImageList[2];
        private Bitmap                              bmpAlpha;
        private Bitmap                              bmpCategory;
        private Bitmap                              bmpPropPage;
 
        // our array of viewTabs
        private bool                                viewTabsDirty = true;
        private bool                                drawFlatToolBar = false;
        private PropertyTab[]                       viewTabs = new PropertyTab[0];
        private PropertyTabScope[]                  viewTabScopes = new PropertyTabScope[0];
        private Hashtable                           viewTabProps;
 
        // the tab view buttons
        private ToolStripButton[]                   viewTabButtons;
        // the index of the currently selected tab view
        private int                                 selectedViewTab;
        
        
        // our view type buttons (Alpha vs. categorized)
        private ToolStripButton[]                   viewSortButtons; 
        private int                                 selectedViewSort;   
        private PropertySort                        propertySortValue;
 
        // this guy's kind of an odd one...he gets special treatment
        private ToolStripButton                     btnViewPropertyPages;
        private ToolStripSeparator                  separator1;
        private ToolStripSeparator                  separator2;
        private int                                 buttonType = NORMAL_BUTTONS;
 
        // our main baby
        private PropertyGridView                    gridView;
 
        
        private IDesignerHost                       designerHost;
        private IDesignerEventService               designerEventService;
        
        private Hashtable                           designerSelections;
 
        private GridEntry peDefault;
        private GridEntry peMain;
        private GridEntryCollection currentPropEntries;
        private Object[]   currentObjects;
        
        private int                                 paintFrozen;
        private Color                               lineColor = SystemInformation.HighContrast ? (AccessibilityImprovements.Level1 ? SystemColors.ControlDarkDark : SystemColors.ControlDark )
                                                                : SystemColors.InactiveBorder;
        internal bool                               developerOverride = false;
        internal Brush                              lineBrush = null;
        private Color                               categoryForeColor = SystemColors.ControlText;
        private Color                               categorySplitterColor = SystemColors.Control;
        private Color                               viewBorderColor = SystemColors.ControlDark;
        private Color                               selectedItemWithFocusForeColor = SystemColors.HighlightText;
        private Color                               selectedItemWithFocusBackColor = SystemColors.Highlight;
        internal Brush                              selectedItemWithFocusBackBrush = null;
        private bool                                canShowVisualStyleGlyphs = true;
 
        private AttributeCollection browsableAttributes;
 
        private SnappableControl                    targetMove = null;
        private int                                 dividerMoveY = -1;
        private const int                    CYDIVIDER = 3;
        private static int                   cyDivider = CYDIVIDER;
        private const int                    CXINDENT = 0;
        private const int                    CYINDENT = 2;
        private const int                    MIN_GRID_HEIGHT = 20;
 
        private const int                    PROPERTIES = 0;
        private const int                    EVENTS = 1;
        private const int                    ALPHA = 1;
        private const int                    CATEGORIES = 0;
        private const int                    NO_SORT = 2;
 
        private const int                    NORMAL_BUTTONS = 0;
        private const int                    LARGE_BUTTONS = 1;
 
        private const int                    TOOLSTRIP_BUTTON_PADDING_Y = 9;
        private int                          toolStripButtonPaddingY = TOOLSTRIP_BUTTON_PADDING_Y;
        private static readonly Size         DEFAULT_LARGE_BUTTON_SIZE = new Size(32, 32);
        private static readonly Size         DEFAULT_NORMAL_BUTTON_SIZE = new Size(16, 16);
        private static Size                  largeButtonSize = DEFAULT_LARGE_BUTTON_SIZE;
        private static Size                  normalButtonSize = DEFAULT_NORMAL_BUTTON_SIZE;
        private static bool                  isScalingInitialized = false;  
 
        private const ushort                  PropertiesChanged          = 0x0001;
        private const ushort                  GotDesignerEventService    = 0x0002;
        private const ushort                  InternalChange             = 0x0004;
        private const ushort                  TabsChanging               = 0x0008;
        private const ushort                  BatchMode                  = 0x0010;
        private const ushort                  ReInitTab                  = 0x0020;
        private const ushort                  SysColorChangeRefresh      = 0x0040;
        private const ushort                  FullRefreshAfterBatch      = 0x0080;
        private const ushort                  BatchModeChange            = 0x0100;
        private const ushort                  RefreshingProperties       = 0x0200;
 
        private ushort                  flags;
 
        private bool GetFlag(ushort flag) {
            return (flags & flag) != (ushort)0;
        }
 
        private void SetFlag(ushort flag, bool value) {
            if (value) {
                flags |= flag;
            }
            else {
                flags &= (ushort)~flag;
            }
        }
 
 
        private readonly ComponentEventHandler                  onComponentAdd;
        private readonly ComponentEventHandler                  onComponentRemove;
        private readonly ComponentChangedEventHandler           onComponentChanged;
        
        // the cookies for our connection points on objects that support IPropertyNotifySink
        //
        private AxHost.ConnectionPointCookie[] connectionPointCookies = null;
 
        private static object          EventPropertyValueChanged = new object();
        private static object          EventComComponentNameChanged = new object();
        private static object          EventPropertyTabChanged = new object();
        private static object          EventSelectedGridItemChanged = new object();
        private static object          EventPropertySortChanged = new object();
        private static object          EventSelectedObjectsChanged = new object();
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyGrid"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
            SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // the "PropertyGridToolBar" caption is for testing.
                                                                                                        // So we don't have to localize it.
        ]
        public PropertyGrid()  {
 
            onComponentAdd = new ComponentEventHandler(OnComponentAdd);
            onComponentRemove = new ComponentEventHandler(OnComponentRemove);
            onComponentChanged = new ComponentChangedEventHandler(OnComponentChanged);
 
            SuspendLayout();
            AutoScaleMode = AutoScaleMode.None;
 
            // static variables are problem in a child level mixed mode scenario. Changing static variables cause compatibility issue. 
            // So, conditioning on new quirk to recalculate static variables everytime property grid initialized.
            if (DpiHelper.EnableDpiChangedHighDpiImprovements) {
                RescaleConstants();
            }
            else {
                if (!isScalingInitialized ) {
                    if (DpiHelper.IsScalingRequired) {
                        normalButtonSize = LogicalToDeviceUnits(DEFAULT_NORMAL_BUTTON_SIZE);
                        largeButtonSize = LogicalToDeviceUnits(DEFAULT_LARGE_BUTTON_SIZE);
                    }
 
                    isScalingInitialized = true;
                }
            }
 
            try
            {
                gridView = CreateGridView(null);
                gridView.TabStop = true;
                gridView.MouseMove += new MouseEventHandler(this.OnChildMouseMove);
                gridView.MouseDown += new MouseEventHandler(this.OnChildMouseDown);
                gridView.TabIndex = 2;
 
                separator1 = CreateSeparatorButton();
                separator2 = CreateSeparatorButton();
 
                toolStrip = AccessibilityImprovements.Level3 ? new PropertyGridToolStrip(this) : new ToolStrip();
                toolStrip.SuspendLayout();
                toolStrip.ShowItemToolTips = true;
                toolStrip.AccessibleName = SR.GetString(SR.PropertyGridToolbarAccessibleName);
                toolStrip.AccessibleRole = AccessibleRole.ToolBar;
                toolStrip.TabStop = true;
                toolStrip.AllowMerge = false;
 
                // This caption is for testing.
                toolStrip.Text = "PropertyGridToolBar";
 
                // LayoutInternal handles positioning, and for perf reasons, we manually size.
                toolStrip.Dock = DockStyle.None;
                toolStrip.AutoSize = false;
                toolStrip.TabIndex = 1;
                toolStrip.ImageScalingSize = normalButtonSize;
 
                // parity with the old... 
                toolStrip.CanOverflow = false;
 
 
                // hide the grip but add in a few more pixels of padding.
                toolStrip.GripStyle = ToolStripGripStyle.Hidden;
                Padding toolStripPadding = toolStrip.Padding;
                toolStripPadding.Left = 2;
                toolStrip.Padding = toolStripPadding;
                SetToolStripRenderer();
 
 
                // always add the property tab here
                AddRefTab(DefaultTabType, null, PropertyTabScope.Static, true);
 
                doccomment = new DocComment(this);
                doccomment.SuspendLayout();
                doccomment.TabStop = false;
                doccomment.Dock = DockStyle.None;
                doccomment.BackColor = SystemColors.Control;
                doccomment.ForeColor = SystemColors.ControlText;
                doccomment.MouseMove += new MouseEventHandler(this.OnChildMouseMove);
                doccomment.MouseDown += new MouseEventHandler(this.OnChildMouseDown);
 
 
 
                hotcommands = new HotCommands(this);
                hotcommands.SuspendLayout();
                hotcommands.TabIndex = 3;
                hotcommands.Dock = DockStyle.None;
                SetHotCommandColors(false);
                hotcommands.Visible = false;
                hotcommands.MouseMove += new MouseEventHandler(this.OnChildMouseMove);
                hotcommands.MouseDown += new MouseEventHandler(this.OnChildMouseDown);
              
                Controls.AddRange(new Control[] { doccomment, hotcommands, gridView, toolStrip });
 
                SetActiveControlInternal(gridView);
                toolStrip.ResumeLayout(false);  // SetupToolbar should perform the layout
                SetupToolbar();
                this.PropertySort = PropertySort.Categorized | PropertySort.Alphabetical;
                this.Text = "PropertyGrid";
                SetSelectState(0);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            finally {
                if (doccomment != null) {
                    doccomment.ResumeLayout(false);
                }
                if (hotcommands != null) {
                    hotcommands.ResumeLayout(false);
                }
                ResumeLayout(true);
            }
        }
 
        internal IDesignerHost ActiveDesigner {
            get{
                if (this.designerHost == null) {
                    designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
                }
                return this.designerHost;
            }
            set{
                if (value != designerHost) {
                    SetFlag(ReInitTab, true);
                    if (this.designerHost != null) {
                        IComponentChangeService cs = (IComponentChangeService)designerHost.GetService(typeof(IComponentChangeService));
                        if (cs != null) {
                            cs.ComponentAdded -= onComponentAdd;
                            cs.ComponentRemoved -= onComponentRemove;
                            cs.ComponentChanged -= onComponentChanged;
                        }
                        
                        IPropertyValueUIService pvSvc = (IPropertyValueUIService)designerHost.GetService(typeof(IPropertyValueUIService));
                        if (pvSvc != null) {
                            pvSvc.PropertyUIValueItemsChanged -= new EventHandler(this.OnNotifyPropertyValueUIItemsChanged);
                        }
                        
                        designerHost.TransactionOpened -= new EventHandler(this.OnTransactionOpened);
                        designerHost.TransactionClosed -= new DesignerTransactionCloseEventHandler(this.OnTransactionClosed);
                        SetFlag(BatchMode, false);
                        RemoveTabs(PropertyTabScope.Document, true);
                        this.designerHost = null;
                    }
 
                    
 
                    if (value != null) {
                        IComponentChangeService cs = (IComponentChangeService)value.GetService(typeof(IComponentChangeService));
                        if (cs != null) {
                            cs.ComponentAdded += onComponentAdd;
                            cs.ComponentRemoved += onComponentRemove;
                            cs.ComponentChanged += onComponentChanged;
                        }
 
                        value.TransactionOpened += new EventHandler(this.OnTransactionOpened);
                        value.TransactionClosed += new DesignerTransactionCloseEventHandler(this.OnTransactionClosed);
                        SetFlag(BatchMode, false);
                        
                        IPropertyValueUIService pvSvc = (IPropertyValueUIService)value.GetService(typeof(IPropertyValueUIService));
                        if (pvSvc != null) {
                            pvSvc.PropertyUIValueItemsChanged += new EventHandler(this.OnNotifyPropertyValueUIItemsChanged);
                        }
                    }
                    
                    designerHost = value;
                    if (peMain != null) {
                        peMain.DesignerHost = value;
                    }
                    RefreshTabs(PropertyTabScope.Document);
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.AutoScroll"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override bool AutoScroll {
            get {
                return base.AutoScroll;
            }
            set {
                base.AutoScroll = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BackColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override Color BackColor {
            get {
                return base.BackColor;
            }
            set {
                base.BackColor = value;
                toolStrip.BackColor = value;
                toolStrip.Invalidate(true);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BackgroundImage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage {
            get {
                return base.BackgroundImage;
            }
            set {
                base.BackgroundImage = value;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BackgroundImageChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged {
            add {
                base.BackgroundImageChanged += value;
            }
            remove {
                base.BackgroundImageChanged -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BackgroundImageLayout"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout {
            get {
                return base.BackgroundImageLayout;
            }
            set {
                base.BackgroundImageLayout = value;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BackgroundImageLayoutChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            }
            remove {
                base.BackgroundImageLayoutChanged -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.BrowsableAttributes"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public AttributeCollection BrowsableAttributes {
            set {
                if (value == null || value == AttributeCollection.Empty) {
                    browsableAttributes = new AttributeCollection(new Attribute[]{BrowsableAttribute.Yes});
                }
                else {
                    Attribute[] attributes = new Attribute[value.Count];
                    value.CopyTo(attributes, 0);
                    browsableAttributes = new AttributeCollection(attributes);
                }
                if (currentObjects != null && currentObjects.Length > 0) {
                    if (peMain != null) {
                        peMain.BrowsableAttributes = BrowsableAttributes;
                        Refresh(true);
                    }
                }
            }
            get {
                if (browsableAttributes == null) {
                    browsableAttributes = new AttributeCollection(new Attribute[]{new BrowsableAttribute(true)});
                }
                return browsableAttributes;
            }
        }
        
        private bool CanCopy {
            get {
                return gridView.CanCopy;
            }
        }
        
        private bool CanCut {
            get {
                return gridView.CanCut;
            }
        }
        
        private bool CanPaste {
            get {
                return gridView.CanPaste;
            }
        }
        
        private bool CanUndo {
            get {
                return gridView.CanUndo;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CanShowCommands"]/*' />
        /// <devdoc>
        /// true if the commands pane will be can be made visible
        /// for the currently selected objects.  Objects that
        /// expose verbs can show commands.
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        SRDescription(SR.PropertyGridCanShowCommandsDesc)]
        public virtual bool CanShowCommands {
            get {
                return hotcommands.WouldBeVisible;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CategoryForeColor"]/*' />
        /// <devdoc>
        /// The text used color for category headings. The background color is determined by the LineColor property.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCategoryForeColorDesc),
        DefaultValue(typeof(Color), "ControlText")
        ]
        public Color CategoryForeColor {
            get {
                return categoryForeColor;
            }
            set {
                if (categoryForeColor != value) {
                    categoryForeColor = value;
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsBackColor"]/*' />
        /// <devdoc>
        /// The background color for the hot commands region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsBackColorDesc)
        ]
        public Color CommandsBackColor {
            get {
                return hotcommands.BackColor;
            }
            set {
                hotcommands.BackColor = value;
                hotcommands.Label.BackColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsForeColor"]/*' />
        /// <devdoc>
        /// The forground color for the hot commands region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsForeColorDesc)
        ]
        public Color CommandsForeColor {
            get {
                return hotcommands.ForeColor;
            }
            set {
                hotcommands.ForeColor = value;
                hotcommands.Label.ForeColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsEnabledLinkColor"]/*' />
        /// <devdoc>
        /// The link color for the hot commands region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsLinkColorDesc)
        ]
        public Color CommandsLinkColor {
            get {
                return hotcommands.Label.LinkColor;
            }
            set {
                hotcommands.Label.LinkColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsActiveLinkColor"]/*' />
        /// <devdoc>
        /// The active link color for the hot commands region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsActiveLinkColorDesc)
        ]
        public Color CommandsActiveLinkColor {
            get {
                return hotcommands.Label.ActiveLinkColor;
            }
            set {
                hotcommands.Label.ActiveLinkColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsDisabledLinkColor"]/*' />
        /// <devdoc>
        /// The color for the hot commands region when the link is disabled.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsDisabledLinkColorDesc)
        ]
        public Color CommandsDisabledLinkColor {
            get {
                return hotcommands.Label.DisabledLinkColor;
            }
            set {
                hotcommands.Label.DisabledLinkColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsBorderColor"]/*' />
        /// <devdoc>
        ///    <para>The border color for the hot commands region</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsBorderColorDesc),
        DefaultValue(typeof(Color), "ControlDark")
        ]
        public Color CommandsBorderColor {
            get {
                return hotcommands.BorderColor;
            }
            set {
                hotcommands.BorderColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsVisible"]/*' />
        /// <devdoc>
        /// Returns true if the commands pane is currently shown.
        /// </devdoc>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public virtual bool CommandsVisible {
            get {
                return hotcommands.Visible;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CommandsVisibleIfAvailable"]/*' />
        /// <devdoc>
        /// Returns true if the commands pane will be shown for objects
        /// that expose verbs.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(true),
        SRDescription(SR.PropertyGridCommandsVisibleIfAvailable)
        ]
        public virtual bool CommandsVisibleIfAvailable {
            get {
                return hotcommands.AllowVisible;
            }
            set {
                bool hotcommandsVisible = hotcommands.Visible;
                hotcommands.AllowVisible = value;
                //PerformLayout();
                if (hotcommandsVisible != hotcommands.Visible) {
                    OnLayoutInternal(false);
                    hotcommands.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ContextMenuDefaultLocation"]/*' />
        /// <devdoc>
        /// Returns a default location for showing the context menu.  This
        /// location is the center of the active property label in the grid, and
        /// is used useful to position the context menu when the menu is invoked
        /// via the keyboard.
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public Point ContextMenuDefaultLocation {
            get {
                return GetPropertyGridView().ContextMenuDefaultLocation;
            }
        }
        
         /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.Controls"]/*' />
         /// <devdoc>
        ///     Collection of child controls.
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new ControlCollection Controls {
            get {
                return base.Controls;
            }
        }
 
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.DefaultSize"]/*' />
        protected override Size DefaultSize {
            get {
                return new Size(130, 130);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.DefaultTabType"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        protected virtual Type DefaultTabType {
            get {
               return typeof(PropertiesTab);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.DrawFlatToolbar"]/*' />
        ///<internalonly/>
        protected bool DrawFlatToolbar {
            get {
                return drawFlatToolBar;
            }
            set {
                if (drawFlatToolBar != value) {
                    drawFlatToolBar = value;
                    SetToolStripRenderer();
                }
 
                SetHotCommandColors(value && !AccessibilityImprovements.Level2);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ForeColor"]/*' />
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Color ForeColor {
            get {
                return base.ForeColor;
            }
            set {
                base.ForeColor = value;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ForeColorChanged"]/*' />
        /// <internalonly/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ForeColorChanged {
            add {
                base.ForeColorChanged += value;
            }
            remove {
                base.ForeColorChanged -= value;
            }
        }
 
        private bool FreezePainting {
            get {
               return paintFrozen > 0;
            }
            set {
               
               if (value && IsHandleCreated && this.Visible) {
                  if (0 == paintFrozen++) {
                     SendMessage(NativeMethods.WM_SETREDRAW, 0, 0);
                  }
               }
               if (!value) {
                  if (paintFrozen == 0) {
                     return;
                  }
               
                  if (0 == --paintFrozen) {
                     SendMessage(NativeMethods.WM_SETREDRAW, 1, 0);
                     Invalidate(true);
                  }
                  
               }
            }
        }
 
        /// <summary>
        /// Gets the help control accessibility object.
        /// </summary>
        internal AccessibleObject HelpAccessibleObject {
            get {
                return doccomment.AccessibilityObject;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.HelpBackColor"]/*' />
        /// <devdoc>
        /// The background color for the help region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpBackColorDesc),
        DefaultValue(typeof(Color), "Control")
        ]
        public Color HelpBackColor {
            get {
                return doccomment.BackColor;
            }
            set {
                doccomment.BackColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.HelpForeColor"]/*' />
        /// <devdoc>
        /// The forground color for the help region.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpForeColorDesc),
        DefaultValue(typeof(Color), "ControlText")
        ]
        public Color HelpForeColor {
            get {
                return doccomment.ForeColor;
            }
            set {
                doccomment.ForeColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.HelpBorderColor"]/*' />
        /// <devdoc>
        ///    <para>The border color for the help region</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpBorderColorDesc),
        DefaultValue(typeof(Color), "ControlDark")
        ]
        public Color HelpBorderColor {
            get {
                return doccomment.BorderColor;
            }
            set {
                doccomment.BorderColor = value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.HelpVisible"]/*' />
        /// <devdoc>
        /// Sets or gets the visiblity state of the help pane.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(true),
        Localizable(true),
        SRDescription(SR.PropertyGridHelpVisibleDesc)
        ]
        public virtual bool HelpVisible {
            get {
                return this.helpVisible;
            }
            set {
                this.helpVisible = value;
 
                doccomment.Visible = value;
                OnLayoutInternal(false);
                Invalidate();
                doccomment.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets the hot commands control accessible object.
        /// </summary>
        internal AccessibleObject HotCommandsAccessibleObject {
            get {
                return hotcommands.AccessibilityObject;
            }
        }
 
        /// <summary>
        /// Gets the main entry accessible object.
        /// </summary>
        internal AccessibleObject GridViewAccessibleObject {
            get {
                return gridView.AccessibilityObject;
            }
        }
 
        /// <summary>
        /// Gets the value indicating whether the main entry is visible.
        /// </summary>
        internal bool GridViewVisible {
            get {
                return gridView != null && gridView.Visible;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedItemWithFocusBackColor"]/*' />
        /// <devdoc>
        ///    <para>Background color for Highlighted text.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridSelectedItemWithFocusBackColorDesc),
        DefaultValue(typeof(Color), "Highlight")
        ]
        public Color SelectedItemWithFocusBackColor {
            get {
                return selectedItemWithFocusBackColor;
            }
            set {
                if (selectedItemWithFocusBackColor != value)
                {
                    selectedItemWithFocusBackColor = value;
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedItemWithFocusForeColor"]/*' />
        /// <devdoc>
        ///    <para>Foreground color for Highlighted (selected) text.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridSelectedItemWithFocusForeColorDesc),
        DefaultValue(typeof(Color), "HighlightText")
        ]
        public Color SelectedItemWithFocusForeColor {
            get {
                return selectedItemWithFocusForeColor;
            }
            set {
                if (selectedItemWithFocusForeColor != value)
                {
                    selectedItemWithFocusForeColor = value;
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.DisabledItemForeColor"]/*' />
        /// <devdoc>
        ///    <para>Foreground color for disabled text in the Grid View</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridDisabledItemForeColorDesc),
        DefaultValue(typeof(Color), "GrayText")
        ]
        public Color DisabledItemForeColor {
            get {
                return gridView.GrayTextColor;
            }
            set {
                gridView.GrayTextColor = value;
                gridView.Invalidate();
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CategorySplitterColor"]/*' />
        /// <devdoc>
        ///    <para>Color for the horizontal splitter line separating property categories.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCategorySplitterColorDesc),
        DefaultValue(typeof(Color), "Control")
        ]
        public Color CategorySplitterColor {
            get {
                return categorySplitterColor;
            }
            set {
                if (categorySplitterColor != value) {
                    categorySplitterColor = value;
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CanShowVisualStyleGlyphs"]/*' />
        /// <devdoc>
        ///    <para>Enable/Disable use of VisualStyle glyph for PropertyGrid node expansion.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCanShowVisualStyleGlyphsDesc),
        DefaultValue(true)
        ]
        public bool CanShowVisualStyleGlyphs {
            get {
                return canShowVisualStyleGlyphs;
            }
            set {
                if (canShowVisualStyleGlyphs != value) {
                    canShowVisualStyleGlyphs = value;
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.InPropertySet"]/*' />
        /// <internalonly/>
        bool IComPropertyBrowser.InPropertySet {
            get {
                return GetPropertyGridView().GetInPropertySet();
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.LineColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridLineColorDesc),
        DefaultValue(typeof(Color), "InactiveBorder")
        ]
        public Color LineColor {
            get {
                return lineColor;
            }
            set {
                if (lineColor != value) {
                    lineColor = value;
                    developerOverride = true;
                    if (lineBrush != null) {
                        lineBrush.Dispose();
                        lineBrush = null;
                    }
                    gridView.Invalidate();
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.Padding"]/*' />
        /// <devdoc>
        ///    <para>
        ///    <para>[To be supplied.]</para>
        ///    </para>
        /// </devdoc>
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public new Padding Padding {
            get { return base.Padding; }
            set { base.Padding = value;}
        }
 
        [
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never)
        ]
        public new event EventHandler PaddingChanged {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertySort"]/*' />
        /// <devdoc>
        /// Sets or gets the current property sort type, which can be
        /// PropertySort.Categorized or PropertySort.Alphabetical.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(PropertySort.CategorizedAlphabetical),
        SRDescription(SR.PropertyGridPropertySortDesc)
        ]
        public PropertySort PropertySort {
            get {
                return propertySortValue;
            }
            set {
                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)PropertySort.NoSort, (int)PropertySort.CategorizedAlphabetical)){
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(PropertySort));
                }
                ToolStripButton newButton;
                
                if ((value & PropertySort.Categorized) != 0) {
                    newButton = viewSortButtons[CATEGORIES];
                }
                else if ((value & PropertySort.Alphabetical) != 0) {
                    newButton = viewSortButtons[ALPHA];
                }
                else {
                    newButton = viewSortButtons[NO_SORT];
                }
                
                GridItem selectedGridItem = SelectedGridItem;
               
               
                OnViewSortButtonClick(newButton, EventArgs.Empty);
            
                this.propertySortValue = value;
                
                if (selectedGridItem != null) {
                    try {
                        SelectedGridItem = selectedGridItem;
                    }
                    catch (System.ArgumentException) {
                        // VSWhidbey#158036. When no row is selected, SelectedGridItem returns grid entry for root
                        // object. But this is not a selectable item. So don't worry if setting SelectedGridItem
                        // cause an argument exception whe ntrying to re-select the root object. Just leave the
                        // the grid with no selected row.
                    }
                }
                
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabs"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public PropertyTabCollection PropertyTabs {
            get {
                return new PropertyTabCollection(this);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedObject"]/*' />
        /// <devdoc>
        /// Sets a single Object into the grid to be browsed.  If multiple
        /// objects are being browsed, this property will return the first
        /// one in the list.  If no objects are selected, null is returned.
        /// </devdoc>
        [
        DefaultValue(null),
        SRDescription(SR.PropertyGridSelectedObjectDesc),
        SRCategory(SR.CatBehavior),
        TypeConverter(typeof(SelectedObjectConverter))
        ]
        public Object SelectedObject {
            get {
                if (currentObjects == null || currentObjects.Length == 0) {
                    return null;
                }
                return currentObjects[0];
            }
            set {
                if (value == null) {
                    SelectedObjects = new object[0];
                }
                else {
                    SelectedObjects = new Object[]{value};
                }
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedObjects"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public object[] SelectedObjects {
            set {   
                try {
                    this.FreezePainting = true;
 
                    SetFlag(FullRefreshAfterBatch, false);
                    if (GetFlag(BatchMode)) {
                       SetFlag(BatchModeChange, false);
                    }
                    
                    gridView.EnsurePendingChangesCommitted();
                                        
                    bool isSame = false;
                    bool classesSame = false;
                    bool showEvents = true;
                    
                    // validate the array coming in
                    if (value != null && value.Length > 0) {
                       for (int count = 0; count < value.Length; count++) {
                           if (value[count] == null) {
                               throw new ArgumentException(SR.GetString(SR.PropertyGridSetNull, count.ToString(CultureInfo.CurrentCulture), value.Length.ToString(CultureInfo.CurrentCulture)));
                           }
                           else if (value[count] is IUnimplemented) {
                               throw new NotSupportedException(SR.GetString(SR.PropertyGridRemotedObject, value[count].GetType().FullName));
                           }
                       }
                    }
                    else {
                        showEvents = false;
                    }
   
                    // make sure we actually changed something before we inspect tabs
                    if (currentObjects != null && value != null &&
                        currentObjects.Length == value.Length) {
                        isSame = true;
                        classesSame = true;
                        for (int i = 0; i < value.Length && (isSame || classesSame); i++) {
                            if (isSame && currentObjects[i] != value[i]) {
                                isSame = false;
                            }
       
                            Type oldType = GetUnwrappedObject(i).GetType();
       
                            Object objTemp = value[i];
       
                            if (objTemp is ICustomTypeDescriptor) {
                                objTemp = ((ICustomTypeDescriptor)objTemp).GetPropertyOwner(null);
                            }
                            Type newType = objTemp.GetType();        
       
                            // check if the types are the same.  If they are, and they 
                            // are COM objects, check their GUID's.  If they are different
                            // or Guid.Emtpy, assume the classes are different.
                            //
                            if (classesSame && 
                                (oldType != newType || oldType.IsCOMObject && newType.IsCOMObject)) {
                                classesSame = false;
                            }
                        }
                    }
       
                    if (!isSame) {
 
                        EnsureDesignerEventService();
 
                        showEvents = showEvents && GetFlag(GotDesignerEventService);
                   
                        SetStatusBox("", "");
                       
                        ClearCachedProps();
 
                        // The default selected entry might still reference the previous selected 
                        // objects. Set it to null to avoid leaks.
                        peDefault = null;
 
                        if (value == null) {
                            currentObjects = new Object[0];
                        }
                        else {
                            currentObjects = (object[])value.Clone();
                        }
                       
                        SinkPropertyNotifyEvents();
                        SetFlag(PropertiesChanged, true);
 
 
                        // Since we are changing the selection, we need to make sure that the
                        // keywords for the currently selected grid entry gets removed
                        if (gridView != null) {
                            // TypeResolutionService is needed to access the HelpKeyword. However,
                            // TypeResolutionService might be disposed when project is closing. We
                            // need swallow the exception in this case.
                            try {
                                gridView.RemoveSelectedEntryHelpAttributes();
                            }
                            catch (COMException) {}
                        }
                                               
                        if (peMain != null) {
                            peMain.Dispose();
                        }
   
                        // throw away any extra component only tabs
                        if (!classesSame && !GetFlag(TabsChanging) && selectedViewTab < viewTabButtons.Length) {
    
                            Type tabType = selectedViewTab == -1 ? null : viewTabs[selectedViewTab].GetType();
                            ToolStripButton viewTabButton = null;
                            RefreshTabs(PropertyTabScope.Component);
                            EnableTabs();
                            if (tabType != null) {
                                for (int i = 0; i < viewTabs.Length;i++) {
                                    if (viewTabs[i].GetType() == tabType && viewTabButtons[i].Visible) {
                                        viewTabButton = viewTabButtons[i];
                                        break;
                                    }
                                }
                            }
                            SelectViewTabButtonDefault(viewTabButton);
                        }
                   
                        // make sure we've also got events on all the objects
                        if (showEvents && viewTabs != null && viewTabs.Length > EVENTS && (viewTabs[EVENTS] is EventsTab)) {
                            showEvents = viewTabButtons[EVENTS].Visible;
                            Object tempObj;
                            PropertyDescriptorCollection events;
                            Attribute[] attrs = new Attribute[BrowsableAttributes.Count];
                            BrowsableAttributes.CopyTo(attrs, 0);
                            
                            Hashtable eventTypes = null;
                            
                            if (currentObjects.Length > 10) {
                               eventTypes = new Hashtable();
                            }
                            
                            for (int i = 0; i < currentObjects.Length && showEvents; i++) {
                               tempObj = currentObjects[i];
                               
                               if (tempObj is ICustomTypeDescriptor) {
                                   tempObj = ((ICustomTypeDescriptor)tempObj).GetPropertyOwner(null);
                               }
                            
                               Type objType = tempObj.GetType();
                            
                               if (eventTypes != null && eventTypes.Contains(objType)) {
                                   continue;
                               }
                               
                               // make sure these things are sited components as well
                               showEvents = showEvents && (tempObj is IComponent && ((IComponent)tempObj).Site != null);
                            
                               // make sure we've also got events on all the objects
                               events =  ((EventsTab)viewTabs[EVENTS]).GetProperties(tempObj, attrs);
                               showEvents = showEvents && events != null && events.Count > 0;
                            
                               if (showEvents && eventTypes != null) {
                                   eventTypes[objType] = objType;
                               }
                            }
                        }
                        ShowEventsButton(showEvents && currentObjects.Length > 0);
                        DisplayHotCommands();
   
                        if (currentObjects.Length == 1) {
                            EnablePropPageButton(currentObjects[0]);
                        }
                        else {
                            EnablePropPageButton(null);
                        }
                        OnSelectedObjectsChanged(EventArgs.Empty);
                    }
   
   
                    /*
       
                    Microsoft, hopefully this won't be a big perf problem, but it looks like we
                           need to refresh even if we didn't change the selected objects.
       
                    if (propertiesChanged) {*/
                    if (!GetFlag(TabsChanging)) {
 
                        // ReInitTab means that we should set the tab back to what is used to be for a given designer.
                        // Basically, if you select an events tab for your designer and double click to go to code, it should
                        // be the events tab when you get back to the designer.
                        //
                        // so we set that bit when designers get switched, and makes sure we select and refresh that tab
                        // when we load.
                        //
                        if (currentObjects.Length > 0 && GetFlag(ReInitTab)) {
                            object designerKey = ActiveDesigner;
 
                            // get the active designer, see if we've stashed away state for it.
                            //
                            if (designerKey != null && designerSelections != null && designerSelections.ContainsKey(designerKey.GetHashCode())) {
                                int nButton = (int)designerSelections[designerKey.GetHashCode()];
 
                                // yep, we know this one.  Make sure it's selected.
                                //
                                if (nButton < viewTabs.Length && (nButton == PROPERTIES || viewTabButtons[nButton].Visible)) {
                                    SelectViewTabButton(viewTabButtons[nButton], true);
                                }
                            }
                            else {
                                Refresh(false);
                            }
                            SetFlag(ReInitTab, false);
                        }
                        else {
                            Refresh(true);
                        }
    
                        if (currentObjects.Length > 0) {
                            SaveTabSelection();
                        }
                    }
                   /*}else {
                       Invalidate();
                       gridView.Invalidate();
                   //}*/
                }
                finally {
                   this.FreezePainting = false;
                }
            }
 
            get 
            {
                if (currentObjects == null) {
                    return new object[0];
                }
                return (object[])currentObjects.Clone();
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedTab"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public PropertyTab SelectedTab {
            get {
                Debug.Assert(selectedViewTab < viewTabs.Length && selectedViewTab >= 0, "Invalid tab selection!");
                return viewTabs[selectedViewTab];
            }
        }
 
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedGridItem"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public GridItem SelectedGridItem {
            get {
                GridItem g = gridView.SelectedGridEntry;
                if (g == null) {
                    return this.peMain;
                }
                return g;
            }
            set {
                gridView.SelectedGridEntry = (GridEntry)value;
            }
        }
       
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ShowFocusCues"]/*' />
        ///<internalonly/>        
        protected internal override bool ShowFocusCues {
            get {
                return true;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.Site"]/*' />
        public override ISite Site {
            get {
                return base.Site;
            }
            set {
               
                // Perf - the base class is possibly going to change the font via ambient properties service
                SuspendAllLayout(this);
               
                base.Site = value;
                gridView.ServiceProvider = value;
 
                if (value == null) {
                    this.ActiveDesigner = null;
                }
                else {
                    this.ActiveDesigner = (IDesignerHost)value.GetService(typeof(IDesignerHost));
                }
                
                ResumeAllLayout(this,true);
 
            }
        }
 
        /// <summary>
        /// Gets the value indicating whether the Property grid is sorted by categories.
        /// </summary>
        internal bool SortedByCategories {
            get {
                return (PropertySort & PropertySort.Categorized) != 0;
            }
        }
 
        [Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text {
            get {
                return base.Text;
            }
            set {
                base.Text = value;
            }
        }
 
        [Browsable(false)]
        new public event EventHandler TextChanged {
            add {
                base.TextChanged += value;
            }
            remove {
                base.TextChanged -= value;
            }
        }
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.LargeButtons"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridLargeButtonsDesc),
        DefaultValue(false)
        ]
        public bool LargeButtons {
            get {
                return buttonType == LARGE_BUTTONS;
            }
            set {
                if (value == (buttonType == LARGE_BUTTONS)) {
                    return;
                }
 
                this.buttonType = (value ?  LARGE_BUTTONS : NORMAL_BUTTONS);
                if (value) {
                    EnsureLargeButtons();
                    if (this.imageList != null && this.imageList[LARGE_BUTTONS] != null) {
                        toolStrip.ImageScalingSize = this.imageList[LARGE_BUTTONS].ImageSize;
                    }
                }
                else {
                    if (this.imageList != null && this.imageList[NORMAL_BUTTONS] != null) {
                        toolStrip.ImageScalingSize = this.imageList[NORMAL_BUTTONS].ImageSize;
                    }
                }
                
                toolStrip.ImageList = imageList[this.buttonType];
                OnLayoutInternal(false);
                Invalidate();
                toolStrip.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets the toolbar control accessibility object.
        /// </summary>
        internal AccessibleObject ToolbarAccessibleObject {
            get {
                return toolStrip.AccessibilityObject;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ToolbarVisible"]/*' />
        /// <devdoc>
        /// Sets or gets the visiblity state of the toolStrip.
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(true),
        SRDescription(SR.PropertyGridToolbarVisibleDesc)
        ]
        public virtual bool ToolbarVisible {
            get {
                return this.toolbarVisible;
            }
            set {
                this.toolbarVisible = value;
 
                toolStrip.Visible = value;
                OnLayoutInternal(false);
                if (value) {
                    SetupToolbar(this.viewTabsDirty);
                }
                Invalidate();
                toolStrip.Invalidate();
            }
        }
 
        // PM team has reviewed and decided on naming changes already
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
        protected ToolStripRenderer ToolStripRenderer {
            get {
                if (toolStrip != null) {
                    return toolStrip.Renderer;
                }
                return null;     
            }
            set {
                if (toolStrip != null) {
                   toolStrip.Renderer = value;               
                }
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ViewBackColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridViewBackColorDesc),
        DefaultValue(typeof(Color), "Window")
        ]
        public Color ViewBackColor {
            get {
                return gridView.BackColor;
            }
            set {
                gridView.BackColor = value;
                gridView.Invalidate();
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ViewForeColor"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridViewForeColorDesc),
        DefaultValue(typeof(Color), "WindowText")
        ]
        public Color ViewForeColor {
            get {
                return gridView.ForeColor;
            }
            set {
                gridView.ForeColor = value;
                gridView.Invalidate();
            
            }
        }
  
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ViewBorderColor"]/*' />
        /// <devdoc>
        ///    <para>Border color for the property grid view.</para>
        /// </devdoc>
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridViewBorderColorDesc),
        DefaultValue(typeof(Color), "ControlDark")
        ]
        public Color ViewBorderColor {
            get {
                return viewBorderColor;
            }
            set {
                if (viewBorderColor != value) {
                    viewBorderColor = value;
                    gridView.Invalidate();
                }
            }
        }
 
        private int AddImage(Bitmap image) {
            
            image.MakeTransparent();
            // Resize bitmap only if resizing is needed in order to avoid image distortion.
            if (DpiHelper.IsScalingRequired && (image.Size.Width != normalButtonSize.Width || image.Size.Height != normalButtonSize.Height)) {
                image = DpiHelper.CreateResizedBitmap(image, normalButtonSize);
            }
            int result = imageList[NORMAL_BUTTONS].Images.Count;
            imageList[NORMAL_BUTTONS].Images.Add(image);
            return result;
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.KeyDown"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyEventHandler KeyDown {
            add {
                base.KeyDown += value;
            }
            remove {
                base.KeyDown -= value;
            }
        }
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.KeyPress"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyPressEventHandler KeyPress {
            add {
                base.KeyPress += value;
            }
            remove {
                base.KeyPress -= value;
            }
        }
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.KeyUp"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyEventHandler KeyUp {
            add {
                base.KeyUp += value;
            }
            remove {
                base.KeyUp -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.MouseDown"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event MouseEventHandler MouseDown {
            add {
                base.MouseDown += value;
            }
            remove {
                base.MouseDown -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.MouseUp"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event MouseEventHandler MouseUp {
            add {
                base.MouseUp += value;
            }
            remove {
                base.MouseUp -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.MouseMove"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event MouseEventHandler MouseMove {
            add {
                base.MouseMove += value;
            }
            remove {
                base.MouseMove -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.MouseEnter"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event EventHandler MouseEnter {
            add {
                base.MouseEnter += value;
            }
            remove {
                base.MouseEnter -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.MouseLeave"]/*' />
        /// <internalonly/><hideinheritance/>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event EventHandler MouseLeave {
            add {
                base.MouseLeave += value;
            }
            remove {
                base.MouseLeave -= value;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyValueChanged"]/*' />
        /// <devdoc> Event that is fired when a property value is modified.</devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyValueChangedDescr)]
        public event PropertyValueChangedEventHandler PropertyValueChanged {
            add {
                Events.AddHandler(EventPropertyValueChanged, value);
            }
            remove {
                Events.RemoveHandler(EventPropertyValueChanged, value);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.ComComponentNameChanged"]/*' />
        ///<internalonly/>        
        event ComponentRenameEventHandler IComPropertyBrowser.ComComponentNameChanged {
            add {
                Events.AddHandler(EventComComponentNameChanged, value);
            }
            remove {
                Events.RemoveHandler(EventComComponentNameChanged, value);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabChanged"]/*' />
        /// <devdoc> Event that is fired when the current view tab is changed, such as changing from Properties to Events</devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyTabchangedDescr)]
        public event PropertyTabChangedEventHandler PropertyTabChanged {
            add {
                Events.AddHandler(EventPropertyTabChanged, value);
            }
            remove {
                Events.RemoveHandler(EventPropertyTabChanged, value);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertySortChanged"]/*' />
        /// <devdoc> Event that is fired when the sort mode is changed.</devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertySortChangedDescr)]
        public event EventHandler PropertySortChanged {
            add {
                Events.AddHandler(EventPropertySortChanged, value);
            }
            remove {
                Events.RemoveHandler(EventPropertySortChanged, value);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelectedGridItemChanged"]/*' />
        /// <devdoc> Event that is fired when the selected GridItem is changed</devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridSelectedGridItemChangedDescr)]
        public event SelectedGridItemChangedEventHandler SelectedGridItemChanged {
            add {
                Events.AddHandler(EventSelectedGridItemChanged, value);
            }
            remove {
                Events.RemoveHandler(EventSelectedGridItemChanged, value);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SelecteObjectsChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridSelectedObjectsChangedDescr)]
        public event EventHandler SelectedObjectsChanged {
            add {
                Events.AddHandler(EventSelectedObjectsChanged, value);
            }
            remove {
                Events.RemoveHandler(EventSelectedObjectsChanged, value);
            }
        }
        
        
        internal void AddTab(Type tabType, PropertyTabScope scope) {
            AddRefTab(tabType, null, scope, true);
        }
 
 
        internal void AddRefTab(Type tabType, Object component, PropertyTabScope type, bool setupToolbar) {
            PropertyTab tab = null;
            int tabIndex = -1;
 
            if (viewTabs != null) {
                // check to see if we've already got a tab of this type
                for (int i = 0; i < viewTabs.Length; i++) {
                    Debug.Assert(viewTabs[i] != null, "Null item in tab array!");
                    if (tabType == viewTabs[i].GetType()) {
                        tab = viewTabs[i];
                        tabIndex = i;
                        break;
                    }
                }
            }
            else {
                tabIndex = 0;
            }
 
            if (tab == null) {
                // the tabs need service providers. The one we hold onto is not good enough,
                // so try to get the one off of the component's site.
                IDesignerHost host = null;
                if (component != null && component is IComponent && ((IComponent) component).Site != null)
                    host = (IDesignerHost) ((IComponent) component).Site.GetService(typeof(IDesignerHost));
 
                try
                {
                    tab = CreateTab(tabType, host);
                }
                catch (Exception e)
                {
                    Debug.Fail("Bad Tab.  We're not going to show it. ", e.ToString());
                    return;
                }
 
                // add it at the end of the array
                if (viewTabs != null) {
                    tabIndex = viewTabs.Length;
 
                    // find the insertion position...special case for event's and properties
                    if (tabType == DefaultTabType) {
                        tabIndex = PROPERTIES;
                    }
                    else if (typeof(EventsTab).IsAssignableFrom(tabType)) {
                        tabIndex = EVENTS;
                    }
                    else {
                        // order tabs alphabetically, we've always got a property tab, so
                        // start after that
                        for (int i = 1; i < viewTabs.Length; i++) {
 
                            // skip the event tab
                            if (viewTabs[i] is EventsTab) {
                                continue;
                            }
 
                            if (String.Compare(tab.TabName, viewTabs[i].TabName, false, CultureInfo.InvariantCulture) < 0) {
                                tabIndex = i;
                                break;
                            }
                        }
                    }
                }
 
                // now add the tab to the tabs array
                PropertyTab[] newTabs = new PropertyTab[viewTabs.Length + 1];
                Array.Copy(viewTabs, 0, newTabs, 0, tabIndex);
                Array.Copy(viewTabs, tabIndex, newTabs, tabIndex + 1, viewTabs.Length - tabIndex);
                newTabs[tabIndex] = tab;
                viewTabs = newTabs;
 
                viewTabsDirty = true;
 
                PropertyTabScope[] newTabScopes = new PropertyTabScope[viewTabScopes.Length + 1];
                Array.Copy(viewTabScopes, 0, newTabScopes, 0, tabIndex);
                Array.Copy(viewTabScopes, tabIndex, newTabScopes, tabIndex + 1, viewTabScopes.Length - tabIndex);
                newTabScopes[tabIndex] = type;
                viewTabScopes = newTabScopes;
 
                Debug.Assert(viewTabs != null, "Tab array destroyed!");
            }
 
            if (tab != null && component != null) {
                try {
                    Object[] tabComps = tab.Components;
                    int oldArraySize = tabComps == null ? 0 : tabComps.Length;
 
                    Object[] newComps = new Object[oldArraySize + 1];
                    if (oldArraySize > 0) {
                        Array.Copy(tabComps, newComps, oldArraySize);
                    }
                    newComps[oldArraySize] = component;
                    tab.Components = newComps;
                }
                catch (Exception e) {
                    Debug.Fail("Bad tab. We're going to remove it.", e.ToString());
                    RemoveTab(tabIndex, false);
                }
            }
 
            if (setupToolbar) {
                SetupToolbar();
                ShowEventsButton(false);
            }
        }        
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CollapseAllGridItems"]/*' />
        /// <devdoc> Collapses all the nodes in the PropertyGrid</devdoc>
        public void CollapseAllGridItems() {
            gridView.RecursivelyExpand(peMain, false, false, -1);
        }
          
        private void ClearCachedProps() {
            if (viewTabProps != null) {
               viewTabProps.Clear();                       
            }
        }  
        
        internal void ClearValueCaches() {
            if (peMain != null) {
               peMain.ClearCachedValues();
            }
        }
 
 
        /// <devdoc>
        /// Clears the tabs of the given scope or smaller.
        /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
        /// </devdoc>
        internal void ClearTabs(PropertyTabScope tabScope) {
            if (tabScope < PropertyTabScope.Document) {
                throw new ArgumentException(SR.GetString(SR.PropertyGridTabScope));
            }
            RemoveTabs(tabScope, true);
        }
 
        #if DEBUG
            internal bool inGridViewCreate = false;
        #endif
 
        /// <summary>
        /// Constructs the new instance of the accessibility object for current PropertyGrid control.
        /// </summary>
        /// <returns></returns>
        protected override AccessibleObject CreateAccessibilityInstance() {
            if (AccessibilityImprovements.Level3) {
                return new PropertyGridAccessibleObject(this);
            }
 
            return base.CreateAccessibilityInstance();
        }
 
        private /*protected virtual*/ PropertyGridView CreateGridView(IServiceProvider sp) {
#if DEBUG
            try {
                    inGridViewCreate = true;
#endif
            return new PropertyGridView(sp, this);
#if DEBUG
            }
            finally {
                    inGridViewCreate = false;
            }   
#endif
        }
 
        private ToolStripSeparator CreateSeparatorButton() {
            ToolStripSeparator button = new ToolStripSeparator();
 
            // On DpiChanged in PerMonV2 scenarios, we need to delegate the new DPI value to
            // the affected ToolStripItems, which become newly created. DpiHelper.DeviceDpi does
            // not have the changed DPI value at this point.
            if (DpiHelper.EnableToolStripPerMonitorV2HighDpiImprovements) {
                button.DeviceDpi = DeviceDpi;
            }
 
            return button;
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.CreatePropertyTab"]/*' />
        protected virtual PropertyTab CreatePropertyTab(Type tabType) {
            return null; 
        }
 
        private PropertyTab CreateTab(Type tabType, IDesignerHost host) {
            PropertyTab tab = CreatePropertyTab(tabType);
 
            if (tab == null) {
                ConstructorInfo constructor = tabType.GetConstructor(new Type[] {typeof(IServiceProvider)});
                Object param = null;
                if (constructor == null) {
    
                    // try a IDesignerHost ctor
                    constructor = tabType.GetConstructor(new Type[] {typeof(IDesignerHost)});
    
                    if (constructor != null) {
                        param = host;
                    }
                }
                else {
                    param = this.Site;
                }
    
    
                if (param != null && constructor != null) {
                    tab = (PropertyTab) constructor.Invoke(new Object[] {param});
                }
                else {
                    // just call the default ctor
                    // SECREVIEW: 332064 this is ok because the PropertyGrid requires FullTrust anyways.
                    tab = (PropertyTab)Activator.CreateInstance(tabType);
                }
            }
 
            Debug.Assert(tab != null, "Failed to create tab!");
 
            if (tab != null) {
                // ensure it's a valid tab
                Bitmap bitmap = tab.Bitmap;
                
                if (bitmap == null)
                    throw new ArgumentException(SR.GetString(SR.PropertyGridNoBitmap, tab.GetType().FullName));
 
                Size size = bitmap.Size;
                if (size.Width != 16 || size.Height != 16) {
                    // resize it to 16x16 if it isn't already.
                    //
                    bitmap = new Bitmap(bitmap, new Size(16,16));
                }
 
                string name = tab.TabName;
                if (name == null || name.Length == 0)
                    throw new ArgumentException(SR.GetString(SR.PropertyGridTabName, tab.GetType().FullName));
 
                // we're good to go!
            }
            return tab;
        }
 
        /*
        private ToolStripButton CreateToggleButton(string toolTipText, int imageIndex, EventHandler eventHandler) {
            ToolStripButton button = new ToolStripButton();
            button.Text = toolTipText;
            button.AutoToolTip = true;
            button.DisplayStyle = ToolStripItemDisplayStyle.Image;
            button.ImageIndex = imageIndex;
            button.Click += eventHandler;
            button.CheckOnClick = true;
            button.ImageScaling = ToolStripItemImageScaling.None;
            return button;
        }
        */
 
        private ToolStripButton CreatePushButton(string toolTipText, int imageIndex, EventHandler eventHandler, bool useCheckButtonRole = false) {
            ToolStripButton button = new ToolStripButton();
 
            // On DpiChanged in PerMonV2 scenarios, we need to delegate the new DPI value to
            // the affected ToolStripItems, which become newly created. DpiHelper.DeviceDpi does
            // not have the changed DPI value at this point.
            if (DpiHelper.EnableToolStripPerMonitorV2HighDpiImprovements) {
                button.DeviceDpi = DeviceDpi;
            }
            button.Text = toolTipText;
            button.AutoToolTip = true;
            button.DisplayStyle = ToolStripItemDisplayStyle.Image;
            button.ImageIndex = imageIndex;
            button.Click += eventHandler;
            button.ImageScaling = ToolStripItemImageScaling.SizeToFit;
 
            if (AccessibilityImprovements.Level1) {
                if (useCheckButtonRole) {
                    button.AccessibleRole = AccessibleRole.CheckButton;
                }
            }
 
            return button;
        }
        
        ///<internalonly/>        
        internal void DumpPropsToConsole() {
            gridView.DumpPropsToConsole(peMain, "");
        }
 
        private void DisplayHotCommands() {
            bool hotCommandsDisplayed = hotcommands.Visible;
 
            IComponent component = null;
            DesignerVerb[] verbs = null;
 
            // We favor the menu command service, since it can give us
            // verbs.  If we fail that, we will go straight to the
            // designer.
            //
            if (currentObjects != null && currentObjects.Length > 0) {
                for (int i = 0; i < currentObjects.Length; i++) {
                    object obj = GetUnwrappedObject(i);
                    if (obj is IComponent) {
                        component = (IComponent)obj;
                        break;
                    }
                }
 
                if (component != null) {
                    ISite site = component.Site;
 
                    if (site != null) {
 
                        IMenuCommandService mcs = (IMenuCommandService)site.GetService(typeof(IMenuCommandService));
                        if (mcs != null) {
 
                            // Got the menu command service.  Let it deal with the set of verbs for
                            // this component.
                            //
                            verbs = new DesignerVerb[mcs.Verbs.Count];
                            mcs.Verbs.CopyTo(verbs, 0);
                        }
                        else {
 
                            // No menu command service.  Go straight to the component's designer.  We
                            // can only do this if the Object count is 1, because desginers do not
                            // support verbs across a multi-selection.
                            //
                            if (currentObjects.Length == 1 && GetUnwrappedObject(0) is IComponent) {
 
                                IDesignerHost designerHost = (IDesignerHost) site.GetService(typeof(IDesignerHost));
                                if (designerHost != null) {
                                    IDesigner designer = designerHost.GetDesigner(component);
                                    if (designer != null) {
                                        verbs = new DesignerVerb[designer.Verbs.Count];
                                        designer.Verbs.CopyTo(verbs, 0);
                                    }
                                }
                            }
                        }
                    }
                }
            }
 
            // VSWhidbey 122645 -- don't show verbs if a prop grid is on the form at design time.
            //s
            if (!DesignMode) {
            
 
                if (verbs != null && verbs.Length > 0) {
                    hotcommands.SetVerbs(component, verbs);
                }
                else {
                    hotcommands.SetVerbs(null, null);
                }
    
                if (hotCommandsDisplayed != hotcommands.Visible) {
                    OnLayoutInternal(false);
                }
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.Dispose"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected override void Dispose(bool disposing) {
 
            if (disposing) {
                // Unhook IDesignerEventService.ActiveDesignerChanged event
                //
                if (GetFlag(GotDesignerEventService)) {                
                    Debug.Assert(designerEventService != null, "GetFlag(GotDesignerEventService) inconsistent with designerEventService == null");
                    if (designerEventService != null) {
                        designerEventService.ActiveDesignerChanged -= new ActiveDesignerEventHandler(this.OnActiveDesignerChanged);
                    }                
                    designerEventService = null;
                    SetFlag(GotDesignerEventService, false);
                }
                this.ActiveDesigner = null;
 
                if (viewTabs != null) {
                    for (int i = 0; i < viewTabs.Length; i++) {
                        viewTabs[i].Dispose();
                    }
                    viewTabs = null;
                }
 
                if (imageList != null) {
                    for (int i = 0; i < imageList.Length; i++) {
                        if(imageList[i] != null) {
                            imageList[i].Dispose();
                        }
                    }
                    imageList = null;
                }
 
                if (bmpAlpha != null) {
                    bmpAlpha.Dispose();
                    bmpAlpha = null;
                }
                
                if (bmpCategory != null) {
                    bmpCategory.Dispose();
                    bmpCategory = null;
                }
                
                if (bmpPropPage != null) {
                    bmpPropPage.Dispose();
                    bmpPropPage = null;
                }
           
                if (lineBrush != null) {
                    lineBrush.Dispose();
                    lineBrush = null;
                }
 
                if (peMain != null) {
                    peMain.Dispose();
                    peMain = null;
                }
 
                if (currentObjects != null) {
                    currentObjects = null;
                    SinkPropertyNotifyEvents();
                }
 
                ClearCachedProps();
                currentPropEntries = null;            
            }
 
            base.Dispose(disposing);
        }
 
        private void DividerDraw(int y) {
            if (y == -1)
                return;
 
            Rectangle rectangle = gridView.Bounds;
            rectangle.Y = y - cyDivider;
            rectangle.Height = cyDivider;
 
            DrawXorBar(this,rectangle);
        }
 
        private SnappableControl DividerInside(int x, int y) {
 
            int useGrid = -1;
 
            if (hotcommands.Visible) {
                Point locDoc = hotcommands.Location;
                if (y >= (locDoc.Y - cyDivider) &&
                    y <= (locDoc.Y + 1)) {
                    return hotcommands;
                }
                useGrid = 0;
            }
 
            if (doccomment.Visible) {
                Point locDoc = doccomment.Location;
                if (y >= (locDoc.Y - cyDivider) &&
                    y <= (locDoc.Y+1)) {
                    return doccomment;
                }
 
                if (useGrid == -1) {
                    useGrid = 1;
                }
            }
 
            // also the bottom line of the grid
            if (useGrid != -1) {
                int gridTop = gridView.Location.Y;
                int gridBottom = gridTop + gridView.Size.Height;
 
                if (Math.Abs(gridBottom - y) <= 1 && y > gridTop) {
                    switch (useGrid) {
                        case 0:
                            return hotcommands;
                        case 1:
                            return doccomment;
                    }
                }
            }
            return null;
        }
 
        private int DividerLimitHigh(SnappableControl target) {
            int high = gridView.Location.Y + MIN_GRID_HEIGHT;
            if (target == doccomment && hotcommands.Visible)
                high += hotcommands.Size.Height + 2;
            return high;
        }
 
        private int DividerLimitMove(SnappableControl target, int y) {
            Rectangle rectTarget = target.Bounds;
 
            int cyNew = y;
 
            // make sure we're not going to make ourselves zero height -- make 15 the min size
            cyNew = Math.Min((rectTarget.Y + rectTarget.Height - 15),cyNew);
 
            // make sure we're not going to make ourselves cover up the grid
            cyNew = Math.Max(DividerLimitHigh(target), cyNew);
 
            // just return what we got here
            return(cyNew);
        }
       
        private static void DrawXorBar(Control ctlDrawTo, Rectangle rcFrame) {
            Rectangle rc = ctlDrawTo.RectangleToScreen(rcFrame);
 
            if (rc.Width < rc.Height) {
                for (int i = 0; i < rc.Width; i++) {
                    ControlPaint.DrawReversibleLine(new Point(rc.X+i, rc.Y), new Point(rc.X+i, rc.Y+rc.Height), ctlDrawTo.BackColor);
                }
            }
            else {
                for (int i = 0; i < rc.Height; i++) {
                    ControlPaint.DrawReversibleLine(new Point(rc.X, rc.Y+i), new Point(rc.X+rc.Width, rc.Y+i), ctlDrawTo.BackColor);
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.DropDownDone"]/*' />
        /// <internalonly/>
        /// <devdoc>
        /// <para>[To be supplied.]</para>
        /// </devdoc>
        void IComPropertyBrowser.DropDownDone() {
            GetPropertyGridView().DropDownDone();
        }
        
        private bool EnablePropPageButton(Object obj) {
            if (obj == null) {
                btnViewPropertyPages.Enabled = false;
                return false;
            }
 
            IUIService uiSvc = (IUIService)GetService(typeof(IUIService));
            bool enable = false;
 
            if (uiSvc != null) {
                enable = uiSvc.CanShowComponentEditor(obj);
            }
            else {
                enable = (TypeDescriptor.GetEditor(obj, typeof(ComponentEditor)) != null);
            }
 
            btnViewPropertyPages.Enabled = enable;
            return enable;
        }
 
        // walk through the current tabs to see if they're all valid for this Object
        private void EnableTabs() {
            if (currentObjects != null) {
                // make sure our toolbars is okay
                SetupToolbar();
 
                Debug.Assert(viewTabs != null, "Invalid tab array");
                Debug.Assert(viewTabs.Length == viewTabScopes.Length && viewTabScopes.Length == viewTabButtons.Length,"Uh oh, tab arrays aren't all the same length! tabs=" + viewTabs.Length.ToString(CultureInfo.InvariantCulture) + ", scopes=" + viewTabScopes.Length.ToString(CultureInfo.InvariantCulture) + ", buttons=" + viewTabButtons.Length.ToString(CultureInfo.InvariantCulture));
 
 
 
                // skip the property tab since it's always valid
                for (int i = 1; i < viewTabs.Length; i++) {
                    Debug.Assert(viewTabs[i] != null, "Invalid tab array entry");
 
                    bool canExtend = true;
                    // make sure the tab is valid for all objects
                    for (int j = 0; j < currentObjects.Length; j++) {
                        try
                        {
                            if (!viewTabs[i].CanExtend(GetUnwrappedObject(j)))
                            {
                                canExtend = false;
                                break;
                            }
                        }
                        catch (Exception e)
                        {
                            Debug.Fail("Bad Tab.  Disable for now.", e.ToString());
                            canExtend = false;
                            break;
                        }
                    }
 
                    if (canExtend != viewTabButtons[i].Visible) {
                        viewTabButtons[i].Visible = canExtend;
                        if (!canExtend && i == selectedViewTab) {
                            SelectViewTabButton(viewTabButtons[PROPERTIES], true);
                        }
                    }
                }
            }
        }
 
        private void EnsureDesignerEventService() {
            if (GetFlag(GotDesignerEventService)) {
                return;
            }
            designerEventService = (IDesignerEventService)GetService(typeof(IDesignerEventService));
            if (designerEventService != null) {
                SetFlag(GotDesignerEventService, true);
                designerEventService.ActiveDesignerChanged += new ActiveDesignerEventHandler(this.OnActiveDesignerChanged);
                OnActiveDesignerChanged(null, new ActiveDesignerEventArgs(null, designerEventService.ActiveDesigner));
            }
        }
 
        private void EnsureLargeButtons() {
            if (this.imageList[LARGE_BUTTONS] == null) {
 
                this.imageList[LARGE_BUTTONS] = new ImageList();
                this.imageList[LARGE_BUTTONS].ImageSize = largeButtonSize;
 
                if (DpiHelper.IsScalingRequired) {
                    AddLargeImage(bmpAlpha);
                    AddLargeImage(bmpCategory);
 
                    foreach (PropertyTab tab in viewTabs) {
                        AddLargeImage(tab.Bitmap);
                    }
 
                    AddLargeImage(bmpPropPage);
                }
                else {
                    ImageList.ImageCollection images = imageList[NORMAL_BUTTONS].Images;
 
                    for (int i = 0; i < images.Count; i++) {
                        if (images[i] is Bitmap) {
                            this.imageList[LARGE_BUTTONS].Images.Add(new Bitmap((Bitmap)images[i], largeButtonSize.Width, largeButtonSize.Height));
                        }
                    }
                }
            }
        }
 
        // this method should be called only inside a if (DpiHelper.IsScalingRequired) clause
        private void AddLargeImage(Bitmap originalBitmap) {
            if (originalBitmap == null) {
                return;
            }
 
            Bitmap largeBitmap = null;
            try {
                Bitmap transparentBitmap = new Bitmap(originalBitmap);
                transparentBitmap.MakeTransparent();
                largeBitmap = DpiHelper.CreateResizedBitmap(transparentBitmap, largeButtonSize);
                transparentBitmap.Dispose();
 
                this.imageList[LARGE_BUTTONS].Images.Add(largeBitmap);
            }
            catch (Exception ex) {
                Debug.Fail("Failed to add a large property grid toolstrip button, " + ex.ToString());
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.EnsurePendingChangesCommitted"]/*' />
        /// <internalonly/>
        bool IComPropertyBrowser.EnsurePendingChangesCommitted() {
 
            // The commits sometimes cause transactions to open
            // and close, which will cause refreshes, which we want to ignore.
            // See ASURT 71390.
            //
            try {
 
                if (this.designerHost != null) {
                    designerHost.TransactionOpened -= new EventHandler(this.OnTransactionOpened);
                    designerHost.TransactionClosed -= new DesignerTransactionCloseEventHandler(this.OnTransactionClosed);
                }
            
                return GetPropertyGridView().EnsurePendingChangesCommitted();
            }
            finally {
                if (this.designerHost != null) {
                    designerHost.TransactionOpened += new EventHandler(this.OnTransactionOpened);
                    designerHost.TransactionClosed += new DesignerTransactionCloseEventHandler(this.OnTransactionClosed);
                }
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ExpandAllGridItems"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void ExpandAllGridItems() {
            gridView.RecursivelyExpand(peMain, false, true, PropertyGridView.MaxRecurseExpand);
        }
 
        private static Type[] GetCommonTabs(Object[] objs, PropertyTabScope tabScope) {
 
            if (objs == null || objs.Length == 0) {
                return new Type[0];
            }
 
            Type[] tabTypes = new Type[5];
            int    types = 0;
            int    i,j,k;
            PropertyTabAttribute tabAttr = (PropertyTabAttribute) TypeDescriptor.GetAttributes(objs[0])[typeof(PropertyTabAttribute)];
 
            if (tabAttr == null) {
                return new Type[0];
            }
 
            // filter out all the types of the current scope
            for (i = 0; i < tabAttr.TabScopes.Length; i++) {
                PropertyTabScope item =  tabAttr.TabScopes[i];
 
                if (item == tabScope) {
                    if (types == tabTypes.Length) {
                        Type[] newTabs = new Type[types * 2];
                        Array.Copy(tabTypes, 0, newTabs, 0, types);
                        tabTypes = newTabs;
                    }
                    tabTypes[types++] = tabAttr.TabClasses[i];
                }
            }
 
            if (types == 0) {
                return new Type[0];
            }
 
            bool found;
 
            for (i = 1; i < objs.Length && types > 0; i++) {
 
                // get the tab attribute
                tabAttr = (PropertyTabAttribute) TypeDescriptor.GetAttributes(objs[i])[typeof(PropertyTabAttribute)];
 
                if (tabAttr == null) {
                    // if this guy has no tabs at all, we can fail right now
                    return new Type[0];
                }
 
                // make sure this guy has all the items in the array,
                // if not, remove the items he doesn't have
                for (j = 0; j < types; j++) {
                    found = false;
                    for (k = 0; k < tabAttr.TabClasses.Length; k++) {
                        if (tabAttr.TabClasses[k] == tabTypes[j]) {
                            found = true;
                            break;
                        }
                    }
 
                    // if we didn't find an item, remove it from the list
                    if (!found) {
                        // swap in with the last item and decrement
                        tabTypes[j] = tabTypes[types-1];
                        tabTypes[types-1] = null;
                        types--;
 
                        // recheck this item since we'll be ending sooner
                        j--;
                    }
                }
            }
 
            Type[] returnTypes = new Type[types];
            if (types > 0) {
                Array.Copy(tabTypes, 0, returnTypes, 0, types);
            }
            return returnTypes;
        }
 
        internal GridEntry GetDefaultGridEntry() {
            if (peDefault == null && currentPropEntries != null) {
                peDefault = (GridEntry)currentPropEntries[0];
            }
            return peDefault;
        }
 
        /// <summary>
        /// Gets the element from point.
        /// </summary>
        /// <param name="point">The point where to search the element.</param>
        /// <returns>The element found in the current point.</returns>
        internal Control GetElementFromPoint(Point point) {
            if (ToolbarAccessibleObject.Bounds.Contains(point)) {
                return toolStrip;
            }
 
            if (GridViewAccessibleObject.Bounds.Contains(point)) {
                return gridView;
            }
 
            if (HotCommandsAccessibleObject.Bounds.Contains(point)) {
                return hotcommands;
            }
 
            if (HelpAccessibleObject.Bounds.Contains(point)) {
                return doccomment;
            }
 
            return null;
        }
 
        private object GetUnwrappedObject(int index) {
            if (currentObjects == null || index < 0 || index > currentObjects.Length) {
                return null;
            }
 
            Object obj = currentObjects[index];
            if (obj is ICustomTypeDescriptor) {
                obj = ((ICustomTypeDescriptor)obj).GetPropertyOwner(null);
            }
            return obj;
        }
 
        internal GridEntryCollection GetPropEntries() {
 
            if (currentPropEntries == null) {
                UpdateSelection();
            }
            SetFlag(PropertiesChanged, false);
            return currentPropEntries;
        }
 
 
        private PropertyGridView GetPropertyGridView() {
            return gridView;
        }
        
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.HandleF4"]/*' />
        /// <internalonly/>
        void IComPropertyBrowser.HandleF4() {
            
            if (gridView.ContainsFocus) {
                return;
            }
        
            if (this.ActiveControl != gridView) {
                this.SetActiveControlInternal(gridView);
            }
            gridView.FocusInternal();
        }
 
        internal bool HavePropEntriesChanged() {
            return GetFlag(PropertiesChanged);
        }
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.LoadState"]/*' />
        /// <internalonly/>
        void IComPropertyBrowser.LoadState(RegistryKey optRoot) {
            if (optRoot != null) {
                Object val = optRoot.GetValue("PbrsAlpha", "0");
 
                if (val != null && val.ToString().Equals("1")) {
                    this.PropertySort = PropertySort.Alphabetical;
                }
                else {
                    this.PropertySort = PropertySort.Categorized | PropertySort.Alphabetical;
                }
 
                val = optRoot.GetValue("PbrsShowDesc", "1");
                this.HelpVisible = (val != null && val.ToString().Equals("1"));
 
                val = optRoot.GetValue("PbrsShowCommands", "0");
                this.CommandsVisibleIfAvailable = (val != null && val.ToString().Equals("1"));
 
 
                val = optRoot.GetValue("PbrsDescHeightRatio", "-1");
 
                bool update = false;
                if (val is string) {
                    int ratio = Int32.Parse((string)val, CultureInfo.InvariantCulture);
                    if (ratio > 0) {
                        dcSizeRatio = ratio;
                        update = true;
                    }
                }
 
                val = optRoot.GetValue("PbrsHotCommandHeightRatio", "-1");
                if (val is string) {
                    int ratio = Int32.Parse((string)val, CultureInfo.InvariantCulture);
                    if (ratio > 0) {
                        dcSizeRatio = ratio;
                        update = true;
                    }
                }
 
                if (update) {
                    OnLayoutInternal(false);
                }
            }
            else {
                // apply the same defaults from above.
                //
                this.PropertySort = PropertySort.Categorized | PropertySort.Alphabetical;
                this.HelpVisible = true;
                this.CommandsVisibleIfAvailable = false;                
            }
        }
 
        // when the active document is changed, check all the components so see if they
        // are offering up any new tabs
        private void OnActiveDesignerChanged(Object sender, ActiveDesignerEventArgs e) {
 
            if (e.OldDesigner != null && e.OldDesigner == designerHost) {
                this.ActiveDesigner = null;
            }
 
            if (e.NewDesigner != null && e.NewDesigner != designerHost) {
                this.ActiveDesigner = e.NewDesigner;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.UnsafeNativeMethods.IPropertyNotifySink.OnChanged"]/*' />
        /// <internalonly/>
        /// <devdoc>
        /// Called when a property on an Ole32 Object changes.
        /// See IPropertyNotifySink::OnChanged
        /// </devdoc>
        void UnsafeNativeMethods.IPropertyNotifySink.OnChanged(int dispID) {
            // we don't want the grid's own property sets doing this, but if we're getting
            // an OnChanged that isn't the DispID of the property we're currently changing,
            // we need to cause a refresh.
            //
            //
            bool fullRefresh = false;
            PropertyDescriptorGridEntry selectedEntry = gridView.SelectedGridEntry as PropertyDescriptorGridEntry;
            if (selectedEntry != null && selectedEntry.PropertyDescriptor != null && selectedEntry.PropertyDescriptor.Attributes != null) {
 
                // fish out the DispIdAttribute which will tell us the DispId of the
                // property that we're changing.
                //
                DispIdAttribute dispIdAttr = (DispIdAttribute)selectedEntry.PropertyDescriptor.Attributes[(typeof(DispIdAttribute))];
                if (dispIdAttr != null && !dispIdAttr.IsDefaultAttribute()) {
                    fullRefresh = (dispID != dispIdAttr.Value);
                }
            }
 
            if (!GetFlag(RefreshingProperties)) {
                if (!gridView.GetInPropertySet() || fullRefresh) {
                    Refresh(fullRefresh);
                }
    
                // this is so changes to names of native
                // objects will be reflected in the combo box
                Object obj = GetUnwrappedObject(0);
                if (ComNativeDescriptor.Instance.IsNameDispId(obj, dispID) || dispID == NativeMethods.ActiveX.DISPID_Name) {
                    OnComComponentNameChanged(new ComponentRenameEventArgs(obj, null, TypeDescriptor.GetClassName(obj)));
                }
            }
        }
 
        /// <devdoc>
        /// We forward messages from several of our children
        /// to our mouse move so we can put up the spliter over their borders
        /// </devdoc>
        private void OnChildMouseMove(Object sender, MouseEventArgs me) {
            Point newPt = Point.Empty;
            if (ShouldForwardChildMouseMessage((Control)sender, me, ref newPt)) {
                // forward the message
                this.OnMouseMove(new MouseEventArgs(me.Button, me.Clicks, newPt.X, newPt.Y, me.Delta));
                return;
            }
        }
 
        /// <devdoc>
        /// We forward messages from several of our children
        /// to our mouse move so we can put up the spliter over their borders
        /// </devdoc>
        private void OnChildMouseDown(Object sender, MouseEventArgs me) {
            Point newPt = Point.Empty;
 
            if (ShouldForwardChildMouseMessage((Control)sender, me, ref newPt)) {
                // forward the message
                this.OnMouseDown(new MouseEventArgs(me.Button, me.Clicks, newPt.X, newPt.Y, me.Delta));
                return;
            }
        }
        
        private void OnComponentAdd(Object sender, ComponentEventArgs e) {
 
            PropertyTabAttribute attribute = (PropertyTabAttribute) TypeDescriptor.GetAttributes(e.Component.GetType())[typeof(PropertyTabAttribute)];
 
            if (attribute == null) {
                return;
            }
 
            // add all the document items
            for (int i=0; i < attribute.TabClasses.Length; i++) {
                if (attribute.TabScopes[i] == PropertyTabScope.Document) {
                    AddRefTab(attribute.TabClasses[i], e.Component, PropertyTabScope.Document, true);
                }
            }
        }
 
        private void OnComponentChanged(Object sender, ComponentChangedEventArgs e) {
            bool batchMode = GetFlag(BatchMode);
            if (batchMode || GetFlag(InternalChange) || gridView.GetInPropertySet() ||
               (currentObjects == null) || (currentObjects.Length == 0)) {
    
                if (batchMode && !gridView.GetInPropertySet()) {
                    SetFlag(BatchModeChange, true);
                }
                return;
            }
 
            int objectCount = currentObjects.Length;
            for (int i = 0; i < objectCount; i++) {
                if (currentObjects[i] == e.Component) {
                    Refresh(false);
                    break;
                }
            }
        }
 
        private void OnComponentRemove(Object sender, ComponentEventArgs e) {
 
            PropertyTabAttribute attribute = (PropertyTabAttribute) TypeDescriptor.GetAttributes(e.Component.GetType())[typeof(PropertyTabAttribute)];
 
            if (attribute == null) {
                return;
            }
 
            // remove all the document items
            for (int i=0; i < attribute.TabClasses.Length; i++) {
                if (attribute.TabScopes[i] == PropertyTabScope.Document) {
                    ReleaseTab(attribute.TabClasses[i], e.Component);
                }
            }
            
            for (int i = 0; i < currentObjects.Length; i++) {
                if (e.Component == currentObjects[i]) {
                    
                        object[] newObjects = new object[currentObjects.Length - 1];
                        Array.Copy(currentObjects, 0, newObjects, 0, i);
                        if (i < newObjects.Length) {
                            // Dev10 Bug 462203: Array.Copy throws Argument Exception when deleting
                            //                   multiple controls with PropertyTabs in designer.
                            Array.Copy(currentObjects, i + 1, newObjects, i, newObjects.Length - i);
                        }
 
                    if (!GetFlag(BatchMode)) {
                        this.SelectedObjects = newObjects;
                    }
                    else {
                        // otherwise, just dump the selection
                        //
                        gridView.ClearProps();
                        this.currentObjects = newObjects;
                        SetFlag(FullRefreshAfterBatch, true);
                    }
                }
            }
 
            SetupToolbar();
            
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnEnabledChanged"]/*' />        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnEnabledChanged(EventArgs e) {
            base.OnEnabledChanged(e);
            Refresh();
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnFontChanged"]/*' />
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnFontChanged(EventArgs e) {
            base.OnFontChanged(e);
            Refresh();
       }
 
        /// <devdoc>
        /// </devdoc>
        internal void OnGridViewMouseWheel(MouseEventArgs e) {
            this.OnMouseWheel(e);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnHandleCreated"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            OnLayoutInternal(false);
            TypeDescriptor.Refreshed += new RefreshEventHandler(this.OnTypeDescriptorRefreshed);
            if (currentObjects != null && currentObjects.Length > 0) {
                Refresh(true);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnHandleDestroyed"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?        
        protected override void OnHandleDestroyed(EventArgs e) {
            TypeDescriptor.Refreshed -= new RefreshEventHandler(this.OnTypeDescriptorRefreshed);
            base.OnHandleDestroyed(e);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnGotFocus"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnGotFocus(EventArgs e) {
        
            base.OnGotFocus(e);
            
            if (this.ActiveControl == null) {
                this.SetActiveControlInternal(gridView);
            }
            else {
                // sometimes the edit is still the active control
                // when it's hidden or disabled...
                if (!this.ActiveControl.FocusInternal()) {
                    this.SetActiveControlInternal(gridView);
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ScaleCore"]/*' />
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override void ScaleCore(float dx, float dy) {
            int sx = (int)Math.Round(Left * dx);
            int sy = (int)Math.Round(Top * dy);
            int sw = Width;
            sw = (int)Math.Round((Left + Width) * dx - sx);
            int sh = Height;
            sh = (int)Math.Round((Top + Height) * dy - sy);
            SetBounds(sx, sy, sw, sh, BoundsSpecified.All);
        }
 
        private void OnLayoutInternal(bool dividerOnly) {
        
            if (!IsHandleCreated || !this.Visible) {
                return;
            }
 
            try {
 
                this.FreezePainting = true;
 
                if (!dividerOnly) {
                    // no toolbar or doc comment or commands, just
                    // fill the whole thing with the grid
                    if (!toolStrip.Visible && !doccomment.Visible && !hotcommands.Visible) {
                        gridView.Location = new Point(0,0);
                        gridView.Size = Size;
                        return;
                    }
 
                    if (toolStrip.Visible) {
 
                        int toolStripWidth = this.Width;
                        int toolStripHeight = ((LargeButtons) ? largeButtonSize : normalButtonSize).Height + toolStripButtonPaddingY; 
                        Rectangle toolStripBounds = new Rectangle(0,1,toolStripWidth, toolStripHeight); 
                        toolStrip.Bounds = toolStripBounds;
                                               
                        int oldY = gridView.Location.Y;
                        gridView.Location = new Point(0, toolStrip.Height + toolStrip.Top);
                        /*if (oldY < gridView.Location.Y) {
                            // since the toolbar doesn't erase it's
                            // background, we'll have to force it to happen here.
                            Brush b = new SolidBrush(BackColor);
                            Graphics g = toolbar.CreateGraphicsInternal();
                            g.FillRectangle(b, toolbar.ClientRectangle);
                            b.Dispose();
                            g.Dispose();
                            toolbar.Invalidate();
                        }*/
                    }
                    else {
                        gridView.Location = new Point(0, 0);
                    }
                }
 
                // now work up from the bottom
                int endSize = Size.Height;
 
                if (endSize < MIN_GRID_HEIGHT) {
                    return;
                }
 
                int maxSpace = endSize - (gridView.Location.Y + MIN_GRID_HEIGHT);
                int height;
 
                // if we're just moving the divider, set the requested heights
                int dcRequestedHeight = 0;
                int hcRequestedHeight = 0;
                int dcOptHeight = 0;
                int hcOptHeight = 0;
 
                if (dividerOnly) {
                    dcRequestedHeight = doccomment.Visible ? doccomment.Size.Height : 0;
                    hcRequestedHeight = hotcommands.Visible ? hotcommands.Size.Height : 0;
                }
                else {
                    if (doccomment.Visible) {
                        dcOptHeight = doccomment.GetOptimalHeight(Size.Width - cyDivider);
                        if (doccomment.userSized) {
                            dcRequestedHeight = doccomment.Size.Height;
                        }
                        else if (dcSizeRatio != -1) {
                            dcRequestedHeight = (this.Height * dcSizeRatio) / 100;
                        }
                        else {
                            dcRequestedHeight = dcOptHeight;
                        }
                    }
 
                    if (hotcommands.Visible) {
                        hcOptHeight = hotcommands.GetOptimalHeight(Size.Width - cyDivider);
                        if (hotcommands.userSized) {
                            hcRequestedHeight = hotcommands.Size.Height;
                        }
                        else if (hcSizeRatio != -1) {
                            hcRequestedHeight = (this.Height * hcSizeRatio) / 100;
                        }
                        else {
                            hcRequestedHeight = hcOptHeight;
                        }
                    }
                }
 
                // place the help comment window
                if (dcRequestedHeight > 0) {
 
                    maxSpace -= cyDivider;
 
                    if (hcRequestedHeight == 0 || (dcRequestedHeight + hcRequestedHeight) < maxSpace) {
                        // full size
                        height = Math.Min(dcRequestedHeight, maxSpace);
                    }
                    else if (hcRequestedHeight > 0 && hcRequestedHeight < maxSpace) {
                        // give most of the space to the hot commands
                        height = maxSpace - hcRequestedHeight;
                    }
                    else {
                        // split the difference
                        height = Math.Min(dcRequestedHeight, maxSpace / 2 - 1);
                    }
 
                    height = Math.Max(height, cyDivider * 2);
 
                    doccomment.SetBounds(0, endSize - height, Size.Width, height);
 
                    // if we've modified the height to less than the optimal, clear the userSized item
                    if (height <= dcOptHeight && height < dcRequestedHeight) {
                        doccomment.userSized = false;
                    }
                    else if (dcSizeRatio != -1 || doccomment.userSized) {
                        dcSizeRatio = (doccomment.Height * 100) / this.Height;
                    }
 
                    doccomment.Invalidate();
                    endSize = doccomment.Location.Y - cyDivider;
                    maxSpace -= height;
                }
 
                // place the hot commands
                if (hcRequestedHeight > 0) {
                    maxSpace -= cyDivider;
 
 
                    if (maxSpace > hcRequestedHeight) {
                        // full size
                        height = Math.Min(hcRequestedHeight, maxSpace);
                    }
                    else {
                        // what's left
                        height = maxSpace;
                    }
 
                    height = Math.Max(height, cyDivider * 2);
 
                    // if we've modified the height, clear the userSized item
                    if (height <= hcOptHeight && height < hcRequestedHeight) {
                        hotcommands.userSized = false;
                    }
                    else if (hcSizeRatio != -1 || hotcommands.userSized) {
                        hcSizeRatio = (hotcommands.Height * 100) / this.Height;
                    }
 
                    hotcommands.SetBounds(0, endSize - height, Size.Width, height);
                    hotcommands.Invalidate();
                    endSize = hotcommands.Location.Y - cyDivider;
                }
 
                gridView.Size = new Size(Size.Width, endSize - gridView.Location.Y);
            }
            finally {
                this.FreezePainting = false;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnMouseDown"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnMouseDown(MouseEventArgs me) {
            SnappableControl target = DividerInside(me.X,me.Y);
            if (target != null && me.Button == MouseButtons.Left) {
                // capture mouse.
                CaptureInternal = true;
                targetMove = target;
                dividerMoveY = me.Y;
                DividerDraw(dividerMoveY);
            }
            base.OnMouseDown(me);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnMouseMove"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnMouseMove(MouseEventArgs me) {
 
            if (dividerMoveY == -1) {
                if (DividerInside(me.X,me.Y) != null) {
                    Cursor = Cursors.HSplit;
                }
                else {
                    Cursor = null;
                }
                return;
            }
 
            int yNew = DividerLimitMove(targetMove, me.Y);
 
            if (yNew != dividerMoveY) {
                DividerDraw(dividerMoveY);
                dividerMoveY = yNew;
                DividerDraw(dividerMoveY);
            }
            base.OnMouseMove(me);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnMouseUp"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnMouseUp(MouseEventArgs me) {
            if (dividerMoveY == -1)
                return;
 
            Cursor = null;
 
            DividerDraw(dividerMoveY);
            dividerMoveY = DividerLimitMove(targetMove, me.Y);
            Rectangle rectDoc = targetMove.Bounds;
            if (dividerMoveY != rectDoc.Y) {
                int yNew = rectDoc.Height + rectDoc.Y - dividerMoveY - (cyDivider / 2); // we subtract two so the mouse is still over the divider
                Size size = targetMove.Size;
                size.Height = Math.Max(0,yNew);
                targetMove.Size = size;
                targetMove.userSized = true;
                OnLayoutInternal(true);
                // invalidate the divider area so we cleanup anything
                // left by the xor
                Invalidate(new Rectangle(0, me.Y - cyDivider, Size.Width, me.Y + cyDivider));
 
                // in case we're doing the top one, we might have wrecked stuff
                // on the grid
                gridView.Invalidate(new Rectangle(0, gridView.Size.Height - cyDivider, Size.Width, cyDivider));
            }
 
            // end the move
            CaptureInternal = false;
            dividerMoveY = -1;
            targetMove = null;
            base.OnMouseUp(me);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.UnsafeNativeMethods.IPropertyNotifySink.OnRequestEdit"]/*' />
        /// <internalonly/>
        /// <devdoc>
        /// Called when a property on an Ole32 Object that is tagged
        /// with "requestedit" is about to be edited.
        /// See IPropertyNotifySink::OnRequestEdit
        /// </devdoc>
        int UnsafeNativeMethods.IPropertyNotifySink.OnRequestEdit(int dispID) {
            // we don't do anything here...
            return NativeMethods.S_OK;
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnResize"]/*' />
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnResize(EventArgs e) {
            if (IsHandleCreated && this.Visible) {
                OnLayoutInternal(false);
            }
            base.OnResize(e);
        }
 
 
 
        private void OnButtonClick(Object sender, EventArgs e) {
            // we don't want to steal focus from the property pages...
            if (sender != btnViewPropertyPages) {
                gridView.FocusInternal();
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnComComponentNameChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected void OnComComponentNameChanged(ComponentRenameEventArgs e) {
            ComponentRenameEventHandler handler = (ComponentRenameEventHandler)Events[EventComComponentNameChanged];
            if (handler != null) handler(this,e);
        }
        
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnNotifyPropertyValueUIItemsChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // Seems safe - doesn't do anything interesting
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected void OnNotifyPropertyValueUIItemsChanged(object sender, EventArgs e) {
            gridView.LabelPaintMargin = 0;
            gridView.Invalidate(true);
        }
  
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnPaint"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // Seems safe - doesn't do anything interesting
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnPaint(PaintEventArgs pevent) {
            
            // just erase the stuff above and below the properties window
            // so we don't flicker.
            Point psheetLoc = gridView.Location;
            int width = Size.Width;
            
            Brush background;
            if (BackColor.IsSystemColor) {
                background = SystemBrushes.FromSystemColor(BackColor);
            }
            else {
                background = new SolidBrush(BackColor);
            }
            pevent.Graphics.FillRectangle(background, new Rectangle(0,0,width, psheetLoc.Y));
 
            int yLast = psheetLoc.Y + gridView.Size.Height;
 
            // fill above hotcommands
            if (hotcommands.Visible) {
                pevent.Graphics.FillRectangle(background, new Rectangle(0, yLast, width, hotcommands.Location.Y - yLast));
                yLast += hotcommands.Size.Height;
            }
 
            // fill above doccomment
            if (doccomment.Visible) {
                pevent.Graphics.FillRectangle(background, new Rectangle(0, yLast, width, doccomment.Location.Y - yLast));
                yLast += doccomment.Size.Height;
            }
 
            // anything that might be left
            pevent.Graphics.FillRectangle(background, new Rectangle(0, yLast, width, Size.Height - yLast));
            
            if (!BackColor.IsSystemColor) {
                background.Dispose();
            }
            base.OnPaint(pevent);
 
            if (lineBrush != null) {
                lineBrush.Dispose();
                lineBrush = null;
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnPropertySortChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // Seems safe - just fires an event
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected virtual void OnPropertySortChanged(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventPropertySortChanged];
            if (handler != null) handler(this,e);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnPropertyTabChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // Seems safe - just fires an event
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected virtual void OnPropertyTabChanged (PropertyTabChangedEventArgs e) {
            PropertyTabChangedEventHandler handler = (PropertyTabChangedEventHandler)Events[EventPropertyTabChanged];
            if (handler != null) handler(this,e);
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnPropertyValueChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // Seems safe - just fires an event
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected virtual void OnPropertyValueChanged(PropertyValueChangedEventArgs e) {
            PropertyValueChangedEventHandler handler = (PropertyValueChangedEventHandler)Events[EventPropertyValueChanged];
            if (handler != null) handler(this,e);
        }
 
        internal void OnPropertyValueSet(GridItem changedItem, object oldValue) {
            OnPropertyValueChanged(new PropertyValueChangedEventArgs(changedItem, oldValue));
 
            // In Level 3 announce the property value change like standalone combobox control do: "[something] selected".
            if (AccessibilityImprovements.Level3 && changedItem != null) {
                    bool dropDown = false;
                Type propertyType = changedItem.PropertyDescriptor.PropertyType;
                UITypeEditor editor = (UITypeEditor)TypeDescriptor.GetEditor(propertyType, typeof(UITypeEditor));
                if (editor != null) {
                    dropDown = editor.GetEditStyle() == UITypeEditorEditStyle.DropDown;
                }
                else {
                    var gridEntry = changedItem as GridEntry;
                    if (gridEntry != null && gridEntry.Enumerable) {
                        dropDown = true;
                    }
                }
 
                if (dropDown && !gridView.DropDownVisible) {
                    this.AccessibilityObject.RaiseAutomationNotification(
                        Automation.AutomationNotificationKind.ActionCompleted,
                        Automation.AutomationNotificationProcessing.All,
                        SR.GetString(SR.PropertyGridPropertyValueSelectedFormat, changedItem.Value));
                }
            }
        }
        
        internal void OnSelectedGridItemChanged(GridEntry oldEntry, GridEntry newEntry) {
            OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs(oldEntry, newEntry));
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnSelectedGridItemChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected virtual void OnSelectedGridItemChanged(SelectedGridItemChangedEventArgs e) {
            SelectedGridItemChangedEventHandler handler = (SelectedGridItemChangedEventHandler)Events[EventSelectedGridItemChanged];
            
            if (handler != null) {
                handler(this, e);
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnSelectedObjectsChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected virtual void OnSelectedObjectsChanged(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventSelectedObjectsChanged];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        private void OnTransactionClosed(object sender, DesignerTransactionCloseEventArgs e) {
            if (e.LastTransaction) {
                // We should not refresh the grid if the selectedObject is no longer sited.
                IComponent currentSelection = SelectedObject as IComponent;
                if (currentSelection != null)
                {
                    if (currentSelection.Site == null) //The component is not logically sited...so clear the PropertyGrid Selection..
                    {
                        //Setting to null... actually will clear off the state information so that ProperyGrid is in sane State.
                        this.SelectedObject = null;
                        return;
                    }
                }
                SetFlag(BatchMode, false);
                if (GetFlag(FullRefreshAfterBatch)) {
                    this.SelectedObjects = currentObjects;
                    SetFlag(FullRefreshAfterBatch, false);
                }
                else if (GetFlag(BatchModeChange)){
                    Refresh(false);
                }
                SetFlag(BatchModeChange, false);
            }
        }
        
        private void OnTransactionOpened(object sender, EventArgs e) {
            SetFlag(BatchMode, true);
        }
 
        private void OnTypeDescriptorRefreshed(RefreshEventArgs e) {
            if (InvokeRequired) {
                BeginInvoke(new RefreshEventHandler(this.OnTypeDescriptorRefreshedInvoke), new object[] { e });
            }
            else {
                OnTypeDescriptorRefreshedInvoke(e);
            }
        }
 
        private void OnTypeDescriptorRefreshedInvoke(RefreshEventArgs e) {
            if (currentObjects != null) {
                for (int i = 0; i < currentObjects.Length; i++) {  
                    Type typeChanged = e.TypeChanged;
                    if (currentObjects[i] == e.ComponentChanged || typeChanged != null && typeChanged.IsAssignableFrom(currentObjects[i].GetType())) {
                        // clear our property hashes
                        ClearCachedProps();
                        Refresh(true);
                        return;
                    }
                }
            }
        }
        
        private void OnViewSortButtonClick(Object sender, EventArgs e) {
            try {
            
               this.FreezePainting = true;
        
               // is this tab selected? If so, do nothing.
               if (sender == viewSortButtons[selectedViewSort]) {
                   viewSortButtons[selectedViewSort].Checked = true;
                   return;
               }
   
               // check new button and uncheck old button.
               viewSortButtons[selectedViewSort].Checked = false;
   
               // find the new button in the list
               int index = 0;
               for (index = 0; index < viewSortButtons.Length; index++) {
                   if (viewSortButtons[index] == sender) {
                       break;
                   }
               }
               
               selectedViewSort = index;
               viewSortButtons[selectedViewSort].Checked = true;
               
               switch (selectedViewSort) {
                  case ALPHA:
                     propertySortValue = PropertySort.Alphabetical;
                     break;
                  case CATEGORIES:
                     propertySortValue = PropertySort.Alphabetical | PropertySort.Categorized;
                     break;
                  case NO_SORT:
                     propertySortValue = PropertySort.NoSort;
                     break;
               }
 
               OnPropertySortChanged(EventArgs.Empty);
               
               Refresh(false);
               OnLayoutInternal(false);
            }
            finally {
               this.FreezePainting = false;
            }
            OnButtonClick(sender, e);
            
        }
 
        private void OnViewTabButtonClick(Object sender, EventArgs e) {
            try {
            
               this.FreezePainting = true;
               SelectViewTabButton((ToolStripButton)sender, true);
               OnLayoutInternal(false);
               SaveTabSelection();
            }
            finally {
               this.FreezePainting = false;
            }
            OnButtonClick(sender, e);
         
        }
 
        private void OnViewButtonClickPP(Object sender, EventArgs e) {
 
            if (btnViewPropertyPages.Enabled &&
                currentObjects != null &&
                currentObjects.Length > 0) {
                Object baseObject = currentObjects[0];
                Object obj = baseObject;
 
                bool success = false;
 
                IUIService uiSvc = (IUIService)GetService(typeof(IUIService));
 
                try {
                    if (uiSvc != null) {
                        success = uiSvc.ShowComponentEditor(obj, this);
                    }
                    else {
                        try {
                            ComponentEditor editor = (ComponentEditor)TypeDescriptor.GetEditor(obj, typeof(ComponentEditor));
                            if (editor != null) {
                                if (editor is WindowsFormsComponentEditor) {
                                    success = ((WindowsFormsComponentEditor)editor).EditComponent(null, obj, (IWin32Window)this);
                                }
                                else {
                                    success = editor.EditComponent(obj);
                                }
                            }
                        }
                        catch {
                        }
                    }
 
                    if (success) {
 
                        if (baseObject is IComponent &&
                            connectionPointCookies[0] == null) {
 
                            ISite site = ((IComponent)baseObject).Site;
                            if (site != null) {
                                IComponentChangeService changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
 
                                if (changeService != null) {
                                    try {
                                        changeService.OnComponentChanging(baseObject, null);
                                    }
                                    catch (CheckoutException coEx) {
                                        if (coEx == CheckoutException.Canceled) {
                                            return;
                                        }
                                        throw coEx;
                                    }
 
                                    try {
                                        // Now notify the change service that the change was successful.
                                        //
                                        SetFlag(InternalChange, true);
                                        changeService.OnComponentChanged(baseObject, null, null, null);
                                    }
                                    finally {
                                        SetFlag(InternalChange, false);
                                    }
 
                                }
                            }
                        }
                        gridView.Refresh();
 
                    }
                }
                catch (Exception ex)
                {
                    String errString = SR.GetString(SR.ErrorPropertyPageFailed);
                    if (uiSvc != null)
                    {
                        uiSvc.ShowError(ex, errString);
                    }
                    else
                    {
                        RTLAwareMessageBox.Show(null, errString, SR.GetString(SR.PropertyGridTitle), MessageBoxButtons.OK, MessageBoxIcon.Error,
                                MessageBoxDefaultButton.Button1, 0);
                    }
                }
            }
            OnButtonClick(sender, e);
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnVisibleChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnVisibleChanged(EventArgs e) {
            base.OnVisibleChanged(e);
            if (Visible && IsHandleCreated) {
                OnLayoutInternal(false);
                SetupToolbar();
            }
        }
 
        /*
            
        /// <summary>
        /// Returns the first child control that can take focus
        /// </summary>
        /// <retval>
        /// Returns null if no control is able to take focus
        /// </retval>
        private Control FirstFocusableChild {
            get {
                if (toolbar.Visible) {
                    return toolbar;
                }
                else if (peMain != null) {
                    return gridView;
                }
                else if (hotcommands.Visible) {
                    return hotcommands;
                }
                else if (doccomment.Visible) {
                    return doccomment;
                }
                return null;
            }
        }
 
        
        private Control LastFocusableChild {
            get {
                if (doccomment.Visible) {
                    return doccomment;
                }
                else if (hotcommands.Visible) {
                    return hotcommands;
                }
                else if (peMain != null) {
                    return gridView;
                }
                else if (toolbar.Visible) {
                    return toolbar;
                }
                return null;
            }
        }
 
        // SECREVIEW: Technically full trust != unmanaged code, therefore this WndProc is at 
        // lesser permission that all the other members in the class.  Practically speaking though
        // they are the same - keeping UnmanagedCode to match the base class.
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        [SuppressMessage("Microsoft.Security", "CA2114:MethodSecurityShouldBeASupersetOfType")]
        protected override bool ProcessDialogKey(Keys keyData) {
            switch (keyData & Keys.KeyCode) {
                case Keys.Tab:
                    // are we going forward?
                    if ((keyData & Keys.Shift) != 0) {
                        // this is backward
                        if (!this.ContainsFocus) {
                            Control lastFocusable = this.LastFocusableChild;
                            
                            if (lastFocusable != null) {
                                lastFocusable.Focus();
                                return true;
                            }
                        }
                    }
                    else {
                    
                        // this is going forward
                        
                        if (!this.ContainsFocus) {
                            Control firstFocusable = this.FirstFocusableChild;
                                
                            if (firstFocusable != null) {
                                firstFocusable.Focus();
                                return true;
                            }
                        }
                     }
                     // properties window is already selected
                     // pass on to parent
                     bool result = base.ProcessDialogKey(keyData);
 
                     // if we're not hosted in a windows forms thing, just give the parent the focus
                     if (!result && this.Parent == null) {
                         int hWndParent = Windows.GetParent(this.Handle);
                         if (hWndParent != 0) {
                             Windows.SetFocus(hWndParent);
                         }
                     }
                     return result;
 
         }
        }
        */
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ProcessDialogKey"]/*' />
        /// <devdoc>
        /// Returns the last child control that can take focus
        /// </devdoc>
        [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
        protected override bool ProcessDialogKey(Keys keyData)
        {
            switch (keyData & Keys.KeyCode) {
                case Keys.Tab:
                     if (((keyData & Keys.Control) != 0) || 
                         ((keyData & Keys.Alt) != 0)) {
                        break;
                     }
                  
                    // are we going forward?
                    if ((keyData & Keys.Shift) != 0) {
                        // this is backward
                        if (hotcommands.Visible && hotcommands.ContainsFocus) {
                            gridView.ReverseFocus();
                        }
                        else if (gridView.FocusInside) {
                            if (toolStrip.Visible) {
                                toolStrip.FocusInternal();
                                if (AccessibilityImprovements.Level1) {
                                    // we need to select first ToolStrip item, otherwise, ToolStrip container has the focus
                                    if (toolStrip.Items.Count > 0) {
                                        toolStrip.SelectNextToolStripItem(null, /*forward =*/ true);
                                    }
                                }
                            }
                            else {
                                return base.ProcessDialogKey(keyData);
                            }
                        }
                        else {
                            // if we get here and the toolbar has focus,
                            // it means we're processing normally, so
                            // pass the focus to the parent
                            if (toolStrip.Focused || !toolStrip.Visible) {
                                return base.ProcessDialogKey(keyData);
                            }
                            else {
                                // otherwise, we're processing a message from elsewhere,
                                // wo we select our bottom guy.
                                if (hotcommands.Visible) {
                                    hotcommands.Select(false);
                                }
                                else if (peMain != null) {
                                    gridView.ReverseFocus();
                                }
                                else if (toolStrip.Visible) {
                                    toolStrip.FocusInternal();
                                }
                                else {
                                    return base.ProcessDialogKey(keyData);
                                }
                            }
                        }
                        return true;
                    }
                    else {
 
                        bool passToParent = false;
 
                        // this is forward
                        if (toolStrip.Focused) {
                            // normal stuff, just do the propsheet
                            if (peMain != null) {
                                gridView.FocusInternal();
                            }
                            else {
                                base.ProcessDialogKey(keyData);
                            }
                            return true;
                        }
                        else if (gridView.FocusInside) {
                            if (hotcommands.Visible) {
                                hotcommands.Select(true);
                                return true;
                            }
                            else {
                                passToParent = true;
                            }
 
                        }
                        else if (hotcommands.ContainsFocus) {
                            passToParent = true;
                        }
                        else {
                            // coming from out side, start with the toolStrip
                            if (toolStrip.Visible) {
                                toolStrip.FocusInternal();
                            }
                            else {
                                gridView.FocusInternal();
                            }
                        }
 
                        // nobody's claimed the focus, pass it on...
                        if (passToParent) {
                            // properties window is already selected
                            // pass on to parent
                            bool result = base.ProcessDialogKey(keyData);
 
                            // if we're not hosted in a windows forms thing, just give the parent the focus
                            if (!result && this.Parent == null) {
                                IntPtr hWndParent = UnsafeNativeMethods.GetParent(new HandleRef(this, Handle));
                                if (hWndParent != IntPtr.Zero) {
                                    UnsafeNativeMethods.SetFocus(new HandleRef(null, hWndParent));
                                }
                            }
                            return result;
                        }
                    }
                    return true;
                /* This conflicts with VS tab linking (ASURT # 31433)
                case Keys.Prior: // PAGE_UP
                    if ((keyData & Keys.Control) != 0) {
                        SelectPriorView();
                        return true;
                    }
                    break;
                case Keys.Next: //PAGE_DOWN
                    if ((keyData & Keys.Control) != 0) {
                        SelectNextView();
                        return true;
                    }
                    break;
                */
 
            }
            return base.ProcessDialogKey(keyData);
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.Refresh"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override void Refresh() {
            if (GetFlag(RefreshingProperties)) {
                return;
            }
 
            Refresh(true);
            base.Refresh();
        }
        
        
        private void Refresh(bool clearCached) {
 
            if (Disposing) {
                return;
            }
        
            if (GetFlag(RefreshingProperties)) {
                return;
            }
 
            try {
               this.FreezePainting = true;
               SetFlag(RefreshingProperties, true);
               
               if (clearCached) {
                  ClearCachedProps();
               }
               RefreshProperties(clearCached);
               gridView.Refresh();
               DisplayHotCommands();
           }
           finally {
               this.FreezePainting = false;
               SetFlag(RefreshingProperties, false);
           }
        }
 
        internal void RefreshProperties(bool clearCached) {
            
            // Clear our current cache so we can do a full refresh.
            if (clearCached && selectedViewTab != -1 && viewTabs != null) {
               PropertyTab tab = viewTabs[selectedViewTab]; 
               if (tab != null && viewTabProps != null) {
                   string tabName = tab.TabName + propertySortValue.ToString();
                   viewTabProps.Remove(tabName);
               }
            }
         
            SetFlag(PropertiesChanged, true);
            UpdateSelection();
        }
 
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.RefreshTabs"]/*' />
        /// <devdoc>
        /// Refreshes the tabs of the given scope by deleting them and requerying objects and documents
        /// for them.
        /// </devdoc>
        public void RefreshTabs(PropertyTabScope tabScope) {
            
            if (tabScope < PropertyTabScope.Document) {
                throw new ArgumentException(SR.GetString(SR.PropertyGridTabScope));
            }
 
            RemoveTabs(tabScope, false);
 
            // check the component level tabs
            if (tabScope <= PropertyTabScope.Component) {
                if (currentObjects != null && currentObjects.Length > 0) {
                    // get the subset of PropertyTabs that's common to all objects
                    Type[] tabTypes = GetCommonTabs(currentObjects, PropertyTabScope.Component);
 
                    for (int i = 0; i < tabTypes.Length; i++) {
                        for (int j = 0; j < currentObjects.Length; j++) {
                            AddRefTab(tabTypes[i], currentObjects[j], PropertyTabScope.Component, false);
                        }
                    }
                }
            }
 
            // check the document level tabs
            if (tabScope <= PropertyTabScope.Document && designerHost != null) {
                IContainer container = designerHost.Container;
                if (container != null) {
                    ComponentCollection components = container.Components;
                    if (components != null) {
                        foreach (IComponent comp in components) {
                            PropertyTabAttribute attribute = (PropertyTabAttribute) TypeDescriptor.GetAttributes(comp.GetType())[typeof(PropertyTabAttribute)];
 
                            if (attribute != null) {
                                for (int j = 0; j < attribute.TabClasses.Length; j++) {
                                    if (attribute.TabScopes[j] == PropertyTabScope.Document) {
                                        AddRefTab(attribute.TabClasses[j], comp, PropertyTabScope.Document, false);
                                    }
                                }
                            }
                        }
                    }
                }
            }
 
            SetupToolbar();
        }
 
        internal void ReleaseTab(Type tabType, Object component) {
            PropertyTab tab = null;
            int tabIndex = -1;
            for (int i = 0; i < viewTabs.Length; i++) {
                if (tabType == viewTabs[i].GetType()) {
                    tab = viewTabs[i];
                    tabIndex = i;
                    break;
                }
            }
 
            if (tab == null) {
                //Debug.Fail("How can we release a tab when it isn't here.");
                return;
            }
 
            Object[] components = tab.Components;
            bool killTab = false;
 
            try {
                int index = -1;
                if (components != null)
                    index = Array.IndexOf(components, component);
 
                if (index >= 0) {
                    object[] newComponents = new object[components.Length - 1];
                    Array.Copy(components, 0, newComponents, 0, index);
                    Array.Copy(components, index + 1, newComponents, index, components.Length - index - 1);
                    components = newComponents;
                    tab.Components = components;
                }
                killTab = (components.Length == 0);
            }
            catch (Exception e)
            {
                Debug.Fail("Bad Tab.  It's going away.", e.ToString());
                killTab = true;
            }
 
            // we don't remove PropertyTabScope.Global tabs here.  Our owner has to do that.
            if (killTab && viewTabScopes[tabIndex] > PropertyTabScope.Global) {
                RemoveTab(tabIndex, false);
            }
        }
 
        private void RemoveImage(int index) {
            imageList[NORMAL_BUTTONS].Images.RemoveAt(index);
            if (imageList[LARGE_BUTTONS] != null) {
                imageList[LARGE_BUTTONS].Images.RemoveAt(index);
            }
        }
 
        // removes all the tabs with a classification greater than or equal to the specified classification.
        // for example, removing PropertyTabScope.Document will remove PropertyTabScope.Document and PropertyTabScope.Component tabs
        internal void RemoveTabs(PropertyTabScope classification, bool setupToolbar) {
            if (classification == PropertyTabScope.Static) {
                throw new ArgumentException(SR.GetString(SR.PropertyGridRemoveStaticTabs));
            }
            
            // in case we've been disposed
            if (viewTabButtons == null || viewTabs == null || viewTabScopes == null) {
                return;
            }
 
            ToolStripButton selectedButton = (selectedViewTab >=0 && selectedViewTab < viewTabButtons.Length ? viewTabButtons[selectedViewTab] : null);
 
            for (int i = viewTabs.Length-1; i >= 0; i--) {
                if (viewTabScopes[i] >= classification) {
 
                    // adjust the selected view tab because we're deleting.
                    if (selectedViewTab == i) {
                        selectedViewTab = -1;
                    }
                    else if (selectedViewTab > i) {
                        selectedViewTab--;
                    }
                    
                    PropertyTab[] newTabs = new PropertyTab[viewTabs.Length - 1];
                    Array.Copy(viewTabs, 0, newTabs, 0, i);
                    Array.Copy(viewTabs, i + 1, newTabs, i, viewTabs.Length - i - 1);
                    viewTabs = newTabs;
 
                    PropertyTabScope[] newTabScopes = new PropertyTabScope[viewTabScopes.Length - 1];
                    Array.Copy(viewTabScopes, 0, newTabScopes, 0, i);
                    Array.Copy(viewTabScopes, i + 1, newTabScopes, i, viewTabScopes.Length - i - 1);
                    viewTabScopes = newTabScopes;
 
                    viewTabsDirty = true;
                }
            }
 
            if (setupToolbar && viewTabsDirty) {
                SetupToolbar();
 
                Debug.Assert(viewTabs != null && viewTabs.Length > 0, "Holy Moly!  We don't have any tabs left!");
 
                selectedViewTab = -1;
                SelectViewTabButtonDefault(selectedButton);
 
                // clear the component refs of the tabs
                for (int i = 0; i < viewTabs.Length; i++) {
                    viewTabs[i].Components = new Object[0];
                }
            }
        }
 
        internal void RemoveTab(int tabIndex, bool setupToolbar) {
            Debug.Assert(viewTabs != null, "Tab array destroyed!");
 
            if (tabIndex >= viewTabs.Length || tabIndex < 0) {
                throw new ArgumentOutOfRangeException("tabIndex", SR.GetString(SR.PropertyGridBadTabIndex));
            }
 
            if (viewTabScopes[tabIndex] == PropertyTabScope.Static) {
                throw new ArgumentException(SR.GetString(SR.PropertyGridRemoveStaticTabs));
            }
 
 
            if (selectedViewTab == tabIndex) {
                selectedViewTab = PROPERTIES;
            }
            
            // Remove this tab from our "last selected" group
            //
            if (!GetFlag(ReInitTab) && ActiveDesigner != null) {
               int hashCode = ActiveDesigner.GetHashCode();
               if (designerSelections != null && designerSelections.ContainsKey(hashCode) && (int)designerSelections[hashCode] == tabIndex) {
                  designerSelections.Remove(hashCode);
               }
            }
 
            ToolStripButton selectedButton = viewTabButtons[selectedViewTab];
 
            PropertyTab[] newTabs = new PropertyTab[viewTabs.Length - 1];
            Array.Copy(viewTabs, 0, newTabs, 0, tabIndex);
            Array.Copy(viewTabs, tabIndex + 1, newTabs, tabIndex, viewTabs.Length - tabIndex - 1);
            viewTabs = newTabs;
 
            PropertyTabScope[] newTabScopes = new PropertyTabScope[viewTabScopes.Length - 1];
            Array.Copy(viewTabScopes, 0, newTabScopes, 0, tabIndex);
            Array.Copy(viewTabScopes, tabIndex + 1, newTabScopes, tabIndex, viewTabScopes.Length - tabIndex - 1);
            viewTabScopes = newTabScopes;
 
            viewTabsDirty = true;
 
            if (setupToolbar) {
                SetupToolbar();
                selectedViewTab = -1;
                SelectViewTabButtonDefault(selectedButton);
            }
        }
 
        internal void RemoveTab(Type tabType) {
            PropertyTab tab = null;
            int tabIndex = -1;
            for (int i = 0; i < viewTabs.Length; i++) {
                if (tabType == viewTabs[i].GetType()) {
                    tab = viewTabs[i];
                    tabIndex = i;
                    break;
                }
            }
 
            // just quit if the tab isn't present.
            if (tabIndex == -1) {
                return;
            }
 
            PropertyTab[] newTabs = new PropertyTab[viewTabs.Length - 1];
            Array.Copy(viewTabs, 0, newTabs, 0, tabIndex);
            Array.Copy(viewTabs, tabIndex + 1, newTabs, tabIndex, viewTabs.Length - tabIndex - 1);
            viewTabs = newTabs;
 
            PropertyTabScope[] newTabScopes = new PropertyTabScope[viewTabScopes.Length - 1];
            Array.Copy(viewTabScopes, 0, newTabScopes, 0, tabIndex);
            Array.Copy(viewTabScopes, tabIndex + 1, newTabScopes, tabIndex, viewTabScopes.Length - tabIndex - 1);
            viewTabScopes = newTabScopes;
            
            viewTabsDirty = true;
            SetupToolbar();
        }
 
        private void ResetCommandsBackColor() {
            hotcommands.ResetBackColor();
        }
 
        private void ResetCommandsForeColor() {
            hotcommands.ResetForeColor();
        }
 
        private void ResetCommandsLinkColor() {
            hotcommands.Label.ResetLinkColor();
        }
 
        private void ResetCommandsActiveLinkColor() {
            hotcommands.Label.ResetActiveLinkColor();
        }
 
        private void ResetCommandsDisabledLinkColor() {
            hotcommands.Label.ResetDisabledLinkColor();
        }
 
        private void ResetHelpBackColor() {
            doccomment.ResetBackColor();
        }
 
        private void ResetHelpForeColor() {
            doccomment.ResetBackColor();
        }
 
        // This method is intended for use in replacing a specific selected root object with
        // another object of the same exact type. Scenario: An immutable root object being
        // replaced with a new instance because one of its properties was changed by the user.
        //
        internal void ReplaceSelectedObject(object oldObject, object newObject) {
            Debug.Assert(oldObject != null && newObject != null && oldObject.GetType() == newObject.GetType());
 
            for (int i = 0; i < currentObjects.Length; ++i) {
                if (currentObjects[i] == oldObject) {
                    currentObjects[i] = newObject;
                    Refresh(true);
                    break;
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ResetSelectedProperty"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void ResetSelectedProperty() {
            GetPropertyGridView().Reset();
        }
 
        private void SaveTabSelection() {
            if (designerHost != null) {
               if (designerSelections == null) {
                   designerSelections = new Hashtable();
               }
               designerSelections[designerHost.GetHashCode()] = selectedViewTab;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.IComPropertyBrowser.SaveState"]/*' />
        /// <internalonly/>
        void IComPropertyBrowser.SaveState(RegistryKey optRoot) {
 
            if (optRoot == null) {
                return;
            }
            
            optRoot.SetValue("PbrsAlpha", (this.PropertySort == PropertySort.Alphabetical ? "1" : "0"));
            optRoot.SetValue("PbrsShowDesc", (this.HelpVisible ? "1" : "0"));
            optRoot.SetValue("PbrsShowCommands", (this.CommandsVisibleIfAvailable ? "1" : "0"));
            optRoot.SetValue("PbrsDescHeightRatio", dcSizeRatio.ToString(CultureInfo.InvariantCulture));
            optRoot.SetValue("PbrsHotCommandHeightRatio", hcSizeRatio.ToString(CultureInfo.InvariantCulture));
       }
       
        void SetHotCommandColors(bool vscompat) {
            if (vscompat) {
                hotcommands.SetColors(SystemColors.Control, SystemColors.ControlText, SystemColors.ActiveCaption, SystemColors.ActiveCaption, SystemColors.ActiveCaption, SystemColors.ControlDark);
            }
            else {
                hotcommands.SetColors(SystemColors.Control, SystemColors.ControlText, Color.Empty, Color.Empty, Color.Empty, Color.Empty);
            }
        }
 
        internal void SetStatusBox(string title,string desc) {
            doccomment.SetComment(title,desc);
        }
 
        private void SelectViewTabButton(ToolStripButton button, bool updateSelection) {
            
                Debug.Assert(viewTabButtons != null, "No view tab buttons to select!");
    
                int oldTab = selectedViewTab;
    
                if (!SelectViewTabButtonDefault(button)) {
                    Debug.Fail("Failed to find the tab!");
                }
                
                if (updateSelection) {
                    Refresh(false);
                }
        }
 
        private bool SelectViewTabButtonDefault(ToolStripButton button) {
                // make sure our selection number is valid
                if (selectedViewTab >= 0 && selectedViewTab >= viewTabButtons.Length) {
                    selectedViewTab = -1;
                }
    
                // is this tab button checked? If so, do nothing.
                if (selectedViewTab >=0 && selectedViewTab < viewTabButtons.Length &&
                    button == viewTabButtons[selectedViewTab]) {
                    viewTabButtons[selectedViewTab].Checked = true;
                    return true;
                }
                
                PropertyTab oldTab = null;
    
                // unselect what's selected
                if (selectedViewTab != -1) {
                    viewTabButtons[selectedViewTab].Checked = false;
                    oldTab = viewTabs[selectedViewTab];
                }
    
                // get the new index of the button
                for (int i = 0; i < viewTabButtons.Length; i++) {
                    if (viewTabButtons[i] == button) {
                        selectedViewTab = i;
                        viewTabButtons[i].Checked = true;
                        try {
                            SetFlag(TabsChanging, true);
                            OnPropertyTabChanged(new PropertyTabChangedEventArgs(oldTab, viewTabs[i]));
                        }
                        finally {
                            SetFlag(TabsChanging, false);
                        }
                        return true;
                    }
                }
    
                // select the first tab if we didn't find that one.
                selectedViewTab = PROPERTIES;
                Debug.Assert(viewTabs[PROPERTIES].GetType() == DefaultTabType, "First item is not property tab!");
                SelectViewTabButton(viewTabButtons[PROPERTIES], false);
                return false;
        }
 
 
 
        private void SetSelectState(int state) {
            
        
            if (state >= (viewTabs.Length * viewSortButtons.Length)) {
                state = 0;
            }
            else if (state < 0) {
                state = (viewTabs.Length * viewSortButtons.Length) - 1;
            }
 
 
            // NOTE: See GetSelectState for the full description
            // of the state transitions
 
            // views == 2 (Alpha || Categories)
            // viewTabs = viewTabs.length
 
            // state -> tab = state / views
            // state -> view = state % views
 
            int viewTypes = viewSortButtons.Length;
            
            if (viewTypes > 0) {
            
                int tab = state / viewTypes;
                int view = state % viewTypes;
    
                Debug.Assert(tab < viewTabs.Length, "Trying to select invalid tab!");
                Debug.Assert(view < viewSortButtons.Length, "Can't select view type > 1");
    
                OnViewTabButtonClick(viewTabButtons[tab], EventArgs.Empty);
                OnViewSortButtonClick(viewSortButtons[view], EventArgs.Empty);
            }
        }
 
        private void SetToolStripRenderer() {
            if (DrawFlatToolbar || (SystemInformation.HighContrast && AccessibilityImprovements.Level1)) {
                // use an office look and feel with system colors 
                ProfessionalColorTable colorTable = new ProfessionalColorTable();
                colorTable.UseSystemColors = true;
                ToolStripRenderer = new ToolStripProfessionalRenderer(colorTable);
            }
            else {
                ToolStripRenderer = new ToolStripSystemRenderer();
            }
        }
        
 
        
        private void SetupToolbar() {
            SetupToolbar(false);
        }
 
        private void SetupToolbar(bool fullRebuild) {
 
            // if the tab array hasn't changed, don't bother to do all
            // this work.
            //
            if (!viewTabsDirty && !fullRebuild) {
                return;
            }
            
            try {
               this.FreezePainting = true;
   
   
               if (imageList[NORMAL_BUTTONS] == null || fullRebuild) {
                   imageList[NORMAL_BUTTONS] = new ImageList();
                   if (DpiHelper.IsScalingRequired) {
                       imageList[NORMAL_BUTTONS].ImageSize = normalButtonSize;
                   }
               }
               
               // setup our event handlers
               EventHandler ehViewTab = new EventHandler(this.OnViewTabButtonClick);
               EventHandler ehViewType = new EventHandler(this.OnViewSortButtonClick);
               EventHandler ehPP = new EventHandler(this.OnViewButtonClickPP);
   
               Bitmap b;
               int i;
   
   
               // we manange the buttons as a seperate list so the toobar doesn't flash
               ArrayList buttonList; 
               
               if (fullRebuild) {
                  buttonList = new ArrayList();
               }
               else {
                  buttonList = new ArrayList(toolStrip.Items);
               }
   
               // setup the view type buttons.  We only need to do this once
               if (viewSortButtons == null || fullRebuild) {
                   viewSortButtons = new ToolStripButton[3];
   
                   int alphaIndex = -1;
                   int categoryIndex = -1;
 
                   try {
                       if (bmpAlpha == null) {
                           bmpAlpha = SortByPropertyImage;
                       }
                       alphaIndex = AddImage(bmpAlpha);
                   }
                   catch (Exception e) {
                       Debug.Fail("Failed to load Alpha bitmap", e.ToString());
                   }
   
                   try {
                       if (bmpCategory == null) {
                           bmpCategory = SortByCategoryImage;
                       }
                       categoryIndex = AddImage(bmpCategory);
                   }
                   catch (Exception e) {
                       Debug.Fail("Failed to load category bitmap", e.ToString());
                   }
   
                   viewSortButtons[ALPHA] = CreatePushButton(SR.GetString(SR.PBRSToolTipAlphabetic), alphaIndex, ehViewType, true);
                   viewSortButtons[CATEGORIES] = CreatePushButton(SR.GetString(SR.PBRSToolTipCategorized), categoryIndex, ehViewType, true);
                   
                   // we create a dummy hidden button for view sort
                   viewSortButtons[NO_SORT] = CreatePushButton("", 0, ehViewType, true);
                   viewSortButtons[NO_SORT].Visible = false;
   
                   // add the viewType buttons and a separator
                   for (i = 0; i < viewSortButtons.Length; i++) {
                       buttonList.Add(viewSortButtons[i]);
                   }
               }
               else {
                   // clear all the items from the toolStrip and image list after the first two
                   int items = buttonList.Count; 
   
                   for (i = items-1; i >= 2; i--) {
                       buttonList.RemoveAt(i);
                   }
   
                   items = imageList[NORMAL_BUTTONS].Images.Count;
   
                   for (i = items-1; i >= 2; i--) {
                       RemoveImage(i);
                   }
               }
   
               buttonList.Add(separator1);
   
               // here's our buttons array
               viewTabButtons = new ToolStripButton[viewTabs.Length];
               bool doAdd = viewTabs.Length > 1;
   
               // if we've only got the properties tab, don't add
               // the button (or we'll just have a properties button that you can't do anything with)
               // setup the view tab buttons
               for (i = 0; i < viewTabs.Length; i++) {
                   try {
                       b = viewTabs[i].Bitmap;
                       viewTabButtons[i] = CreatePushButton(viewTabs[i].TabName, AddImage(b), ehViewTab, true);
                       if (doAdd) {
                           buttonList.Add(viewTabButtons[i]);
                       }
                   }
                   catch (Exception ex) {
                       Debug.Fail(ex.ToString());
                   }
               }
   
               // if we didn't add anything, we don't need another separator either.
               if (doAdd) {
                   buttonList.Add(separator2);
               }
   
               // add the design page button
               int designpg = 0;
 
               try {
                   if (bmpPropPage == null) {
                       bmpPropPage = ShowPropertyPageImage;
                   }
                   designpg = AddImage(bmpPropPage);
               }
               catch (Exception e) {
                   Debug.Fail(e.ToString());
               }
   
               // we recreate this every time to ensure it's at the end
               //
               btnViewPropertyPages = CreatePushButton(SR.GetString(SR.PBRSToolTipPropertyPages), designpg, ehPP, false);
               btnViewPropertyPages.Enabled = false;
               buttonList.Add(btnViewPropertyPages);
   
               // Dispose this so it will get recreated for any new buttons.
               if (imageList[LARGE_BUTTONS] != null) {
                   imageList[LARGE_BUTTONS].Dispose();
                   imageList[LARGE_BUTTONS] = null;
               }
   
               if (buttonType != NORMAL_BUTTONS) {
                   EnsureLargeButtons();
               }
   
               toolStrip.ImageList = imageList[this.buttonType];
 
               toolStrip.SuspendLayout();
               toolStrip.Items.Clear();
               for (int j = 0; j < buttonList.Count; j++) {
                    toolStrip.Items.Add(buttonList[j] as ToolStripItem);
               }
               toolStrip.ResumeLayout();
               
               if (viewTabsDirty) {
                  // if we're redoing our tabs make sure
                  // we setup the toolbar area correctly.
                  //
                  OnLayoutInternal(false);
               }
               
               viewTabsDirty = false;
           }
           finally {
               this.FreezePainting = false;
           }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ShowEventsButton"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected void ShowEventsButton(bool value) {
            if (viewTabs != null && viewTabs.Length > EVENTS && (viewTabs[EVENTS] is EventsTab)) {
               
                Debug.Assert(viewTabButtons != null && viewTabButtons.Length > EVENTS && viewTabButtons[EVENTS] != null, "Events button is not at EVENTS position");
                viewTabButtons[EVENTS].Visible = value;
                if (!value && selectedViewTab == EVENTS) {
                    SelectViewTabButton(viewTabButtons[PROPERTIES], true);
                }
            }
 
            UpdatePropertiesViewTabVisibility();            
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SortByPropertyImage"]/*' />
        /// <devdoc>
        /// This 16x16 Bitmap is applied to the button which orders properties alphabetically.
        /// </devdoc>      
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        protected virtual Bitmap SortByPropertyImage {
            get {
                return new Bitmap(typeof(PropertyGrid), "PBAlpha.bmp");
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.SortByCategoryImage"]/*' />
        /// <devdoc>
        /// This 16x16 Bitmap is applied to the button which displays properties under the assigned categories.
        /// </devdoc>
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        protected virtual Bitmap SortByCategoryImage {
            get {
                return new Bitmap(typeof(PropertyGrid), "PBCatego.bmp");
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.ShowPropertyPageImage"]/*' />
        /// <devdoc>
        /// This 16x16 Bitmap is applied to the button which displays property page in the designer pane.
        /// </devdoc>
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        protected virtual Bitmap ShowPropertyPageImage {
            get {
                return new Bitmap(typeof(PropertyGrid), "PBPPage.bmp");
            }
        }
 
        private bool ShouldSerializeCommandsBackColor() {
            return hotcommands.ShouldSerializeBackColor();
        }
 
        private bool ShouldSerializeCommandsForeColor() {
            return hotcommands.ShouldSerializeForeColor();
        }
 
        private bool ShouldSerializeCommandsLinkColor() {
            return hotcommands.Label.ShouldSerializeLinkColor();
        }
 
        private bool ShouldSerializeCommandsActiveLinkColor() {
            return hotcommands.Label.ShouldSerializeActiveLinkColor();
        }
 
        private bool ShouldSerializeCommandsDisabledLinkColor() {
            return hotcommands.Label.ShouldSerializeDisabledLinkColor();
        }
 
        /// <devdoc>
        ///  Sinks the property notify events on all the objects we are currently
        ///  browsing.
        ///
        ///  See IPropertyNotifySink
        /// </devdoc>
        private void SinkPropertyNotifyEvents() {
            // first clear any existing sinks.
            for (int i = 0;connectionPointCookies != null && i < connectionPointCookies.Length; i++) {
                if (connectionPointCookies[i] != null) {
                    connectionPointCookies[i].Disconnect();
                    connectionPointCookies[i] = null;
                }
            }
 
            if (currentObjects == null || currentObjects.Length == 0) {
                connectionPointCookies = null;
                return;
            }
 
            // it's okay if our array is too big...we'll just reuse it and ignore the empty slots.
            if (connectionPointCookies == null || (currentObjects.Length > connectionPointCookies.Length)) {
                connectionPointCookies = new AxHost.ConnectionPointCookie[currentObjects.Length];
            }
            
            for (int i = 0; i < currentObjects.Length; i++) {
                try {
                    Object obj = GetUnwrappedObject(i);
 
                    if (!Marshal.IsComObject(obj)) {
                        continue;
                    }
                    connectionPointCookies[i] = new AxHost.ConnectionPointCookie(obj, this, typeof(UnsafeNativeMethods.IPropertyNotifySink), /*throwException*/ false);
                }
                catch {
                    // guess we failed eh?
                }
            }
        }
 
        private bool ShouldForwardChildMouseMessage(Control child, MouseEventArgs me, ref Point pt) {
 
            Size size = child.Size;
 
            // are we within two pixels of the edge?
            if (me.Y <= 1 || (size.Height - me.Y) <= 1) {
                // convert the coordinates to
                NativeMethods.POINT temp = new NativeMethods.POINT();
                temp.x = me.X;
                temp.y = me.Y;
                UnsafeNativeMethods.MapWindowPoints(new HandleRef(child, child.Handle), new HandleRef(this, Handle), temp, 1);
 
                // forward the message
                pt.X = temp.x;
                pt.Y = temp.y;
                return true;
            }
            return false;
        }
 
        private void UpdatePropertiesViewTabVisibility() {
            // If the only view available is properties-view, there's no need to show the button.
            //
            if (viewTabButtons != null) {
                int nOtherViewsVisible = 0;
                for(int i=1; i < viewTabButtons.Length; i++) { // Starts at index 1, since index 0 is properties-view
                    if (viewTabButtons[i].Visible) {
                        nOtherViewsVisible++;
                    }
                }
                if (nOtherViewsVisible > 0) {
                    viewTabButtons[PROPERTIES].Visible = true;
                    separator2.Visible = true;
                }
                else {
                    viewTabButtons[PROPERTIES].Visible = false;
                    separator2.Visible = false;
                }
            }
        }
 
        internal void UpdateSelection() {
 
            if (!GetFlag(PropertiesChanged)) {
                return;
            }
            
            if (viewTabs == null) {
                return;
            }
            
            string tabName = viewTabs[selectedViewTab].TabName + propertySortValue.ToString();
 
            if (viewTabProps != null && viewTabProps.ContainsKey(tabName)) {
               peMain = (GridEntry)viewTabProps[tabName];
               if (peMain != null) {
                   peMain.Refresh();
               }
            }
            else {
               if (currentObjects != null && currentObjects.Length > 0) {
                   peMain = (GridEntry)GridEntry.Create(gridView, currentObjects, new PropertyGridServiceProvider(this), designerHost, this.SelectedTab, propertySortValue);
               }
               else {
                   peMain = null;
               }
   
               if (peMain == null) {
                   currentPropEntries = new GridEntryCollection(null, new GridEntry[0]);
                   gridView.ClearProps();
                   return;
               }
   
               if (BrowsableAttributes != null) {
                   peMain.BrowsableAttributes = BrowsableAttributes;
               }
 
               if (viewTabProps == null) {
                    viewTabProps = new Hashtable();
               }
               
               viewTabProps[tabName] = peMain;
            }
 
            // get entries.
            currentPropEntries = peMain.Children;
            peDefault = peMain.DefaultChild;
            gridView.Invalidate();
        }
 
        /// <devdoc>
        ///     Determines whether to use compatible text rendering engine (GDI+) or not (GDI).
        /// </devdoc>
        [
        DefaultValue(false),
        SRCategory(SR.CatBehavior),
        SRDescription(SR.UseCompatibleTextRenderingDescr)
        ]
        public bool UseCompatibleTextRendering {
            get{
                return base.UseCompatibleTextRenderingInt;
            }
            set{
                base.UseCompatibleTextRenderingInt = value;
                doccomment.UpdateTextRenderingEngine();
                gridView.Invalidate();
            }
        }
 
        /// <summary>
        /// Indicates whether or not the control supports UIA Providers via
        /// IRawElementProviderFragment/IRawElementProviderFragmentRoot interfaces.
        /// </summary>
        internal override bool SupportsUiaProviders {
            get {
                return AccessibilityImprovements.Level3 && !DesignMode;
            }
        }
 
        /// <devdoc>
        ///     Determines whether the control supports rendering text using GDI+ and GDI.
        ///     This is provided for container controls to iterate through its children to set UseCompatibleTextRendering to the same
        ///     value if the child control supports it.
        /// </devdoc>
        internal override bool SupportsUseCompatibleTextRendering {
            get {
                return true;
            }
        }
 
        internal override bool AllowsKeyboardToolTip() {
            return false;
        }
 
        // a mini version of process dialog key
        // for responding to WM_GETDLGCODE
        internal bool WantsTab(bool forward) {
            if (forward) {
                return toolStrip.Visible && toolStrip.Focused;
            }
            else {
                return gridView.ContainsFocus && toolStrip.Visible;
            }
        }
 
        private string propName;
        private int    dwMsg;
 
        private void GetDataFromCopyData(IntPtr lparam) {
            NativeMethods.COPYDATASTRUCT cds = (NativeMethods.COPYDATASTRUCT)UnsafeNativeMethods.PtrToStructure(lparam, typeof(NativeMethods.COPYDATASTRUCT));
 
            if (cds != null && cds.lpData != IntPtr.Zero) {
                propName = Marshal.PtrToStringAuto(cds.lpData);
                dwMsg = cds.dwData;
            }
        }
        
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.OnSystemColorsChanged"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        // SECREVIEW: This seems safe, but could anything dangerous occur here?
        protected override void OnSystemColorsChanged(EventArgs e) {
            // refresh the toolbar buttons
            SetupToolbar(true);
            
            // this doesn't stick the first time we do it...
            // either probably a toolbar issue, maybe GDI+, so we call it again
            // fortunately this doesn't happen very often.
            //
            if (!GetFlag(SysColorChangeRefresh)) {
               SetupToolbar(true);
               SetFlag(SysColorChangeRefresh, true);
            }
            base.OnSystemColorsChanged(e);
        }
 
        /// <summary>
        /// Rescaling constants.
        /// </summary>
        private void RescaleConstants() {
            normalButtonSize = LogicalToDeviceUnits(DEFAULT_NORMAL_BUTTON_SIZE);
            largeButtonSize = LogicalToDeviceUnits(DEFAULT_LARGE_BUTTON_SIZE);
            cyDivider = LogicalToDeviceUnits(CYDIVIDER);
            toolStripButtonPaddingY = LogicalToDeviceUnits(TOOLSTRIP_BUTTON_PADDING_Y);
 
            if (hotcommands != null && hotcommands.Visible) {
                // Require a fontchange notification
                this.Controls.Remove(hotcommands);
                this.Controls.Add(hotcommands);
            }
        }
 
        /// <summary>
        /// Rescale constants when DPI changed
        /// </summary>
        /// <param name="deviceDpiOld">old dpi</param>
        /// <param name="deviceDpiNew">new dpi</param>
        protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) {
            base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew);
            if (DpiHelper.EnableDpiChangedHighDpiImprovements) {
                RescaleConstants();
                SetupToolbar(true);
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.WndProc"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // SECREVIEW: Technically full trust != unmanaged code, therefore this WndProc is at 
        // lesser permission that all the other members in the class.  Practically speaking though
        // they are the same - keeping UnmanagedCode to match the base class.
        [SuppressMessage("Microsoft.Security", "CA2114:MethodSecurityShouldBeASupersetOfType")]
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
 
            switch (m.Msg) {
                case NativeMethods.WM_UNDO:
                    if ((long)m.LParam == 0) {
                        gridView.DoUndoCommand();
                    }
                    else {
                        m.Result = CanUndo ? (IntPtr)1 : (IntPtr)0;
                    }
                    return;
                case NativeMethods.WM_CUT:
                    if ((long)m.LParam == 0) {
                        gridView.DoCutCommand();
                    }
                    else {
                        m.Result = CanCut ? (IntPtr)1 : (IntPtr)0;
                    }
                    return;
 
                case NativeMethods.WM_COPY:
                    if ((long)m.LParam == 0) {
                        gridView.DoCopyCommand();
                    }
                    else {
                        m.Result = CanCopy ? (IntPtr)1 : (IntPtr)0;
                    }
                    return;
 
                case NativeMethods.WM_PASTE:
                    if ((long)m.LParam == 0) {
                        gridView.DoPasteCommand();
                    }
                    else {
                        m.Result = CanPaste ? (IntPtr)1 : (IntPtr)0;
                    }
                    return;
                
                case NativeMethods.WM_COPYDATA:
                    GetDataFromCopyData(m.LParam);
                    m.Result = (IntPtr)1;
                    return;
                case AutomationMessages.PGM_GETBUTTONCOUNT:
                    if (toolStrip != null) {
                        m.Result = (IntPtr)toolStrip.Items.Count;
                        return;
                    }
                    break;
                case AutomationMessages.PGM_GETBUTTONSTATE:
                    if (toolStrip != null) {
                        int index = unchecked((int)(long)m.WParam);
                        if( index >= 0 && index < toolStrip.Items.Count ) {
                            ToolStripButton button = toolStrip.Items[index] as ToolStripButton;
                            if (button != null) {
                                m.Result = (IntPtr)(button.Checked ? 1 : 0);
                            }
                            else {
                                m.Result = IntPtr.Zero;
                            }
                        }
                        return;
                    }
                    break;
                case AutomationMessages.PGM_SETBUTTONSTATE:
                    if (toolStrip != null) {
                        int index = unchecked((int)(long)m.WParam);
                        if( index >= 0 && index < toolStrip.Items.Count ) {
                            ToolStripButton button = toolStrip.Items[index] as ToolStripButton;
 
                            if (button != null) {
                                button.Checked = !button.Checked;
                                // special treatment for the properies page button
                                if (button == btnViewPropertyPages) {
                                    OnViewButtonClickPP(button, EventArgs.Empty);
                                }
                                else {
                                    switch (unchecked((int)(long)m.WParam)) {
                                        case ALPHA:
                                        case CATEGORIES:
                                            OnViewSortButtonClick(button, EventArgs.Empty);
                                            break;
                                        default:
                                            SelectViewTabButton(button, true);
                                            break;
                                    }
                                }
                            }
                        }
                        return;
                    }
                    break;
 
                case AutomationMessages.PGM_GETBUTTONTEXT:
                case AutomationMessages.PGM_GETBUTTONTOOLTIPTEXT:
                    if (toolStrip != null) {
                        int index = unchecked((int)(long)m.WParam);
                        if( index >= 0 && index < toolStrip.Items.Count ) {
                            string text = "";
                            if (m.Msg == AutomationMessages.PGM_GETBUTTONTEXT) {
                                text = toolStrip.Items[index].Text;
                            }
                            else {
                                text = toolStrip.Items[index].ToolTipText;
                            }
 
                            // write text into test file.
                            m.Result = AutomationMessages.WriteAutomationText(text);
                        }
                        return;
                    }
                    break;
                    
                case AutomationMessages.PGM_GETTESTINGINFO: {
                    // Get "testing info" string for Nth grid entry (or active entry if N < 0)
                    string testingInfo = gridView.GetTestingInfo(unchecked((int) (long) m.WParam));
                    m.Result = AutomationMessages.WriteAutomationText(testingInfo);
                    return;
                    }
                    
                case AutomationMessages.PGM_GETROWCOORDS:
                    if (m.Msg == this.dwMsg) {
                        m.Result = (IntPtr) gridView.GetPropertyLocation(propName, m.LParam == IntPtr.Zero, m.WParam == IntPtr.Zero);
                        return;
                    }
                    break;
                case AutomationMessages.PGM_GETSELECTEDROW:
                case AutomationMessages.PGM_GETVISIBLEROWCOUNT:
                    m.Result = gridView.SendMessage(m.Msg, m.WParam, m.LParam);
                    return;
                case AutomationMessages.PGM_SETSELECTEDTAB:
                    if( m.LParam != IntPtr.Zero ) {
                        string tabTypeName = AutomationMessages.ReadAutomationText(m.LParam);
 
                        for (int i = 0; i < viewTabs.Length;i++) {
                           if (viewTabs[i].GetType().FullName == tabTypeName && viewTabButtons[i].Visible) {
                               SelectViewTabButtonDefault(viewTabButtons[i]);
                               m.Result = (IntPtr)1;
                               break;
                           }
                        }
                    }
                    m.Result = (IntPtr)0;
                    return;
            }
 
            base.WndProc(ref m);
        }
 
        internal abstract class SnappableControl : Control {
            private Color borderColor = SystemColors.ControlDark;
            protected PropertyGrid ownerGrid;
            internal bool userSized = false;
 
            public abstract int GetOptimalHeight(int width);
            public abstract int SnapHeightRequest(int request);
            
            public SnappableControl(PropertyGrid ownerGrid) {
                this.ownerGrid = ownerGrid;
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            }
 
            public override Cursor Cursor {
                 get {
                     return Cursors.Default;
                 }
                 set {
                     base.Cursor = value;
                 }
            }
 
 
            protected override void OnControlAdded(ControlEventArgs ce) {
                //ce.Control.MouseEnter += new EventHandler(this.OnChildMouseEnter);
            }
            
            /*
            private void OnChildMouseEnter(object sender, EventArgs e) {
                if (sender is Control) {
                    ((Control)sender).Cursor = Cursors.Default;
                }
            }
            */
 
            public Color BorderColor {
                get {
                    return borderColor;
                }
                set {
                    borderColor = value;
                }
            }
 
            protected override void OnPaint(PaintEventArgs e) {
                base.OnPaint(e);
                Rectangle r = this.ClientRectangle;
                r.Width --;
                r.Height--;
                using (Pen borderPen = new Pen(BorderColor, 1)) {
                    e.Graphics.DrawRectangle(borderPen, r);
                }
            }
        }
 
        /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")]
        [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
        public class PropertyTabCollection : ICollection {
        
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            internal static PropertyTabCollection Empty = new PropertyTabCollection(null);
            
            private  PropertyGrid   owner;
    
            internal PropertyTabCollection(PropertyGrid owner) {
                this.owner = owner;
            }
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.Count"]/*' />
            /// <devdoc>
            ///     Retrieves the number of member attributes.
            /// </devdoc>
            public int Count {
                get {
                    if (owner == null) {
                        return 0;
                    }
                    return owner.viewTabs.Length;
                }
            }
    
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyTabCollection.ICollection.SyncRoot"]/*' />
            /// <internalonly/>
            object ICollection.SyncRoot {
                get {
                    return this;
                }
            }
    
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyTabCollection.ICollection.IsSynchronized"]/*' />
            /// <internalonly/>
            bool ICollection.IsSynchronized {
                get {
                    return false;
                }
            }
    
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.this"]/*' />
            /// <devdoc>
            ///     Retrieves the member attribute with the specified index.
            /// </devdoc>
            public PropertyTab this[int index] {
                get {
                    if (owner == null) {
                        throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                    }
                    return owner.viewTabs[index];
                }
            }
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.AddTabType"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddTabType(Type propertyTabType) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.AddTab(propertyTabType, PropertyTabScope.Global);
            }
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.AddTabType1"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void AddTabType(Type propertyTabType, PropertyTabScope tabScope) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.AddTab(propertyTabType, tabScope);
            }
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.Clear"]/*' />
            /// <devdoc>
            /// Clears the tabs of the given scope or smaller.
            /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
            /// </devdoc>
            public void Clear(PropertyTabScope tabScope) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.ClearTabs(tabScope);
            }
            
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyTabCollection.ICollection.CopyTo"]/*' />
            /// <internalonly/>
            void ICollection.CopyTo(Array dest, int index) {
                if (owner == null) {
                    return;
                }
                if (owner.viewTabs.Length > 0) {
                    System.Array.Copy(owner.viewTabs, 0, dest, index, owner.viewTabs.Length);
                }
            }
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.GetEnumerator"]/*' />
            /// <devdoc>
            ///      Creates and retrieves a new enumerator for this collection.
            /// </devdoc>
            public IEnumerator GetEnumerator() {
                if (owner == null) {
                    return new PropertyTab[0].GetEnumerator();
                }
                
                return owner.viewTabs.GetEnumerator();
            }
            
            /// <include file='doc\PropertyGrid.uex' path='docs/doc[@for="PropertyGrid.PropertyTabCollection.RemoveTabType"]/*' />
            /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            public void RemoveTabType(Type propertyTabType) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.RemoveTab(propertyTabType);
            }
    
        }
 
        /// <devdoc>
        ///     An unimplemented interface.  What is this?  It is an interface that nobody ever
        ///     implements, of course? Where and why would it be used?  Why, to find cross-process
        ///     remoted objects, of course!  If a well-known object comes in from a cross process
        ///     connection, the remoting layer does contain enough type information to determine
        ///     if an object implements an interface.  It assumes that if you are going to cast
        ///     an object to an interface that you know what you're doing, and allows the cast,
        ///     even for objects that DON'T actually implement the interface.  The error here
        ///     is raised later when you make your first call on that interface pointer:  you
        ///     get a remoting exception.
        ///
        ///     This is a big problem for code that does "is" and "as" checks to detect the
        ///     presence of an interface.  We do that all over the place here, so we do a check
        ///     during parameter validation to see if an object implements IUnimplemented.  If it
        ///     does, we know that what we really have is a lying remoting proxy, and we bail.
        /// </devdoc>
        private interface IUnimplemented {}
 
 
        internal class SelectedObjectConverter : ReferenceConverter {
            public SelectedObjectConverter() : base(typeof(IComponent)) {
            }
        }
 
        private class PropertyGridServiceProvider : IServiceProvider {
            PropertyGrid owner;
            
            public PropertyGridServiceProvider(PropertyGrid owner) {
                this.owner = owner;
            }
 
            public object GetService(Type serviceType) {
               object s = null;
               
               if (owner.ActiveDesigner != null) {
                   s = owner.ActiveDesigner.GetService(serviceType);
               }
 
               if (s == null) {
                   s = owner.gridView.GetService(serviceType);
               }
 
               if (s == null && owner.Site != null) {
                   s = owner.Site.GetService(serviceType);
               }
               return s;
            }
        }
    
        /// <devdoc>
        ///     Helper class to support rendering text using either GDI or GDI+.
        /// </devdoc>
        internal static class MeasureTextHelper{
            public static SizeF MeasureText(PropertyGrid owner, Graphics g, string text, Font font ){
                return MeasureTextSimple(owner, g, text, font, new SizeF(0,0));
            }
 
            public static SizeF MeasureText(PropertyGrid owner, Graphics g, string text, Font font, int width ){
                return MeasureText(owner, g, text, font, new SizeF(width,999999));
            }
 
            public static SizeF MeasureTextSimple(PropertyGrid owner, Graphics g, string text, Font font, SizeF size ){
                SizeF bindingSize;
                if( owner.UseCompatibleTextRendering ){
                    bindingSize = g.MeasureString(text, font, size );
                }
                else{
                    bindingSize = (SizeF) TextRenderer.MeasureText(g, text, font, Size.Ceiling(size), GetTextRendererFlags() );
                }
 
                return bindingSize;
            }
 
            public static SizeF MeasureText(PropertyGrid owner, Graphics g, string text, Font font, SizeF size ){
                SizeF bindingSize;
                if( owner.UseCompatibleTextRendering ){
                    bindingSize = g.MeasureString(text, font, size );
                }
                else{
                    TextFormatFlags flags = 
                        GetTextRendererFlags()                |
                        TextFormatFlags.LeftAndRightPadding   |
                        TextFormatFlags.WordBreak             |
                        TextFormatFlags.NoFullWidthCharacterBreak;
                    
                    bindingSize = (SizeF) TextRenderer.MeasureText(g, text, font, Size.Ceiling(size), flags );
                }
 
                return bindingSize;
            }
 
            public static TextFormatFlags GetTextRendererFlags(){
                return  TextFormatFlags.PreserveGraphicsClipping | 
                        TextFormatFlags.PreserveGraphicsTranslateTransform;
            }
        }    
    }
 
    internal static class AutomationMessages {
        private const int WM_USER = NativeMethods.WM_USER;
        internal const int PGM_GETBUTTONCOUNT = WM_USER + 0x50;
        internal const int PGM_GETBUTTONSTATE = WM_USER + 0x52;
        internal const int PGM_SETBUTTONSTATE = WM_USER + 0x51;
        internal const int PGM_GETBUTTONTEXT = WM_USER + 0x53;
        internal const int PGM_GETBUTTONTOOLTIPTEXT = WM_USER + 0x54;
        internal const int PGM_GETROWCOORDS = WM_USER + 0x55;
        internal const int PGM_GETVISIBLEROWCOUNT = WM_USER + 0x56;
        internal const int PGM_GETSELECTEDROW = WM_USER + 0x57;
        internal const int PGM_SETSELECTEDTAB = WM_USER + 0x58; // DO NOT CHANGE THIS : VC uses it!
        internal const int PGM_GETTESTINGINFO = WM_USER + 0x59;
 
        /// <summary>
        ///     Writes the specified text into a temporary file of the form %TEMP%\"Maui.[file id].log", where 
        ///     'file id' is a unique id that is return by this method.
        ///     This is to support MAUI interaction with the PropertyGrid control and MAUI should remove the 
        ///     file after used.
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static IntPtr WriteAutomationText(string text)
        {
            IntPtr fileId = IntPtr.Zero;
            string fullFileName = GenerateLogFileName(ref fileId);
 
            if (fullFileName != null)
            {
                try
                {
                    FileStream fs = new FileStream(fullFileName, FileMode.Create, FileAccess.Write);
                    StreamWriter sw = new StreamWriter(fs);
                    sw.WriteLine(text);
                    sw.Dispose();
                    fs.Dispose();
                }
                catch
                {
                    fileId = IntPtr.Zero;
                }
            }
 
            return fileId;
        }
 
        /// <summary>
        ///     Writes the contents of a test file as text.  This file needs to have the following naming convention:
        ///     %TEMP%\"Maui.[file id].log", where 'file id' is a unique id sent to this window.
        ///     This is to support MAUI interaction with the PropertyGrid control and MAUI should create/delete this file.
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static string ReadAutomationText(IntPtr fileId)
        {
            Debug.Assert(fileId != IntPtr.Zero, "Invalid file Id");
 
            string text = null;
 
            if (fileId != IntPtr.Zero)
            {
                string fullFileName = GenerateLogFileName(ref fileId);
                Debug.Assert(File.Exists(fullFileName), "Automation log file does not exist");
 
                if (File.Exists(fullFileName))
                {
                    try
                    {
                        FileStream fs = new FileStream(fullFileName, FileMode.Open, FileAccess.Read);
                        StreamReader sr = new StreamReader(fs);
                        text = sr.ReadToEnd();
                        sr.Dispose();
                        fs.Dispose();
                    }
                    catch
                    {
                        text = null;
                    }
                }
            }
 
            return text;
        }
 
        /// <summary>
        ///     Generate log file from id.
        /// </summary>
        private static string GenerateLogFileName(ref IntPtr fileId)
        {
            string fullFileName = null;
 
            string filePath = System.Environment.GetEnvironmentVariable("TEMP");
            Debug.Assert(filePath != null, "Could not get value of the TEMP environment variable");
 
            if (filePath != null)
            {
                if (fileId == IntPtr.Zero) // Create id
                {
                    Random rnd = new Random(DateTime.Now.Millisecond);
                    fileId = new IntPtr(rnd.Next());
                }
 
                fullFileName = filePath + "\\Maui" + fileId + ".log";
            }
 
            return fullFileName;
        }
    }
 
    /// <summary>
    /// Represents the PropertyGrid accessibility object.
    /// Is used only in Accessibility Improvements of level3 to show correct accessible hierarchy.
    /// </summary>
    [ComVisible(true)]
    internal class PropertyGridAccessibleObject : Control.ControlAccessibleObject {
 
        private PropertyGrid _owningPropertyGrid;
 
        /// <summary>
        /// Initializes new instance of PropertyGridAccessibleObject
        /// </summary>
        /// <param name="owningPropertyGrid">The PropertyGrid owning control.</param>
        public PropertyGridAccessibleObject(PropertyGrid owningPropertyGrid) : base(owningPropertyGrid) {
            _owningPropertyGrid = owningPropertyGrid;
        }
 
        /// <summary>
        /// Return the child element at the specified point, if one exists,
        /// otherwise return this element if the point is on this element,
        /// otherwise return null.
        /// </summary>
        /// <param name="x">x coordinate of point to check</param>
        /// <param name="y">y coordinate of point to check</param>
        /// <returns>Return the child element at the specified point, if one exists,
        /// otherwise return this element if the point is on this element,
        /// otherwise return null.
        /// </returns>
        internal override UnsafeNativeMethods.IRawElementProviderFragment ElementProviderFromPoint(double x, double y) {
            Point clientPoint = _owningPropertyGrid.PointToClient(new Point((int)x, (int)y));
 
            var element = _owningPropertyGrid.GetElementFromPoint(clientPoint);
            if (element != null) {
                return element.AccessibilityObject;
            }
 
            return base.ElementProviderFromPoint(x, y);
        }
 
        /// <summary>
        /// Request to return the element in the specified direction.
        /// </summary>
        /// <param name="direction">Indicates the direction in which to navigate.</param>
        /// <returns>Returns the element in the specified direction.</returns>
        internal override UnsafeNativeMethods.IRawElementProviderFragment FragmentNavigate(UnsafeNativeMethods.NavigateDirection direction) {
            switch(direction) {
                case UnsafeNativeMethods.NavigateDirection.Parent:
                    return null;
                case UnsafeNativeMethods.NavigateDirection.FirstChild:
                    return GetChildFragment(0);
                case UnsafeNativeMethods.NavigateDirection.LastChild:
                    var childFragmentCount = GetChildFragmentCount();
                    if (childFragmentCount > 0) {
                        return GetChildFragment(childFragmentCount - 1);
                    }
                    break;
            }
 
            return base.FragmentNavigate(direction);
        }
 
        /// <summary>
        /// Request to return the element in the specified direction regarding the provided child element.
        /// </summary>
        /// <param name="childFragment">The child element regarding which the target element is searched.</param>
        /// <param name="direction">Indicates the direction in which to navigate.</param>
        /// <returns>Returns the element in the specified direction.</returns>
        internal UnsafeNativeMethods.IRawElementProviderFragment ChildFragmentNavigate(AccessibleObject childFragment, UnsafeNativeMethods.NavigateDirection direction) {
            switch(direction) {
                case UnsafeNativeMethods.NavigateDirection.Parent:
                    return this;
                case UnsafeNativeMethods.NavigateDirection.NextSibling:
                    int fragmentCount = GetChildFragmentCount();
                    int childFragmentIndex = GetChildFragmentIndex(childFragment);
                    int nextChildFragmentIndex = childFragmentIndex + 1;
                    if (fragmentCount > nextChildFragmentIndex) {
                        return GetChildFragment(nextChildFragmentIndex);
                    }
 
                    return null;
                case UnsafeNativeMethods.NavigateDirection.PreviousSibling:
                    fragmentCount = GetChildFragmentCount();
                    childFragmentIndex = GetChildFragmentIndex(childFragment);
                    if (childFragmentIndex > 0) {
                        return GetChildFragment(childFragmentIndex - 1);
                    }
 
                    return null;
            }
 
            return null;
        }
 
        /// <summary>
        /// Return the element that is the root node of this fragment of UI.
        /// </summary>
        internal override UnsafeNativeMethods.IRawElementProviderFragmentRoot FragmentRoot {
            get {
                return this;
            }
        }
 
        /// <summary>
        /// Gets the accessible child corresponding to the specified index.</para>
        /// </summary>
        /// <param name="index">The child index.</param>
        /// <returns>The accessible child.</returns>
        internal AccessibleObject GetChildFragment(int index) {
            if (index < 0) {
                return null;
            }
            
            if (_owningPropertyGrid.ToolbarVisible) {
                if (index == 0) {
                    return _owningPropertyGrid.ToolbarAccessibleObject;
                }
 
                index--;
            }
 
            if (_owningPropertyGrid.GridViewVisible) {
                if (index == 0) {
                    return _owningPropertyGrid.GridViewAccessibleObject;
                }
 
                index--;
            }
            
            if (_owningPropertyGrid.CommandsVisible) {
                if (index == 0) {
                    return _owningPropertyGrid.HotCommandsAccessibleObject;
                }
 
                index--;
            }
            
            if (_owningPropertyGrid.HelpVisible) {
                if (index == 0) {
                    return _owningPropertyGrid.HelpAccessibleObject;
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Gets the number of children belonging to an accessible object.
        /// </summary>
        /// <returns>The number of children.</returns>
        internal int GetChildFragmentCount() {
            int childCount = 0;
 
            if (_owningPropertyGrid.ToolbarVisible) {
                childCount++;
            }
 
            if (_owningPropertyGrid.GridViewVisible) {
                childCount++;
            }
 
            if (_owningPropertyGrid.CommandsVisible) {
                childCount++;
            }
 
            if (_owningPropertyGrid.HelpVisible) {
                childCount++;
            }
 
            return childCount;
        }
 
        /// <summary>
        /// Return the element in this fragment which has the keyboard focus,
        /// </summary>
        /// <returns>Return the element in this fragment which has the keyboard focus,
        /// if any; otherwise return null.</returns>
        internal override UnsafeNativeMethods.IRawElementProviderFragment GetFocus() {
            return GetFocused();
        }
 
        /// <summary>
        /// Gets the child control index.
        /// </summary>
        /// <param name="controlAccessibleObject">The control accessible object which index should be found.</param>
        /// <returns>The child accessible index or -1 if not found.</returns>
        internal int GetChildFragmentIndex(AccessibleObject controlAccessibleObject) {
            int childFragmentCount = GetChildFragmentCount();
            for (int i = 0; i < childFragmentCount; i++) {
                var childFragment = GetChildFragment(i);
                if (childFragment == controlAccessibleObject) {
                    return i;
                }
            }
 
            return -1;
        }
    }
 
    /// <summary>
    /// Represents the PropertyGrid inner ToolStrip control.
    /// Is used starting with Accessibility Improvements of level 3.
    /// </summary>
    internal class PropertyGridToolStrip : ToolStrip {
 
        private PropertyGrid _parentPropertyGrid;
 
        /// <summary>
        /// Initializes new instance of PropertyGridToolStrip control.
        /// </summary>
        /// <param name="parentPropertyGrid">The parent PropertyGrid control.</param>
        public PropertyGridToolStrip(PropertyGrid parentPropertyGrid) {
            _parentPropertyGrid = parentPropertyGrid;
        }
 
        /// <summary>
        /// Indicates whether or not the control supports UIA Providers via
        /// IRawElementProviderFragment/IRawElementProviderFragmentRoot interfaces.
        /// </summary>
        internal override bool SupportsUiaProviders {
            get {
                return true;
            }
        }
 
        /// <summary>
        /// Constructs the new instance of the accessibility object for this control.
        /// </summary>
        /// <returns>The accessibility object for this control.</returns>
        protected override AccessibleObject CreateAccessibilityInstance() {
            return new PropertyGridToolStripAccessibleObject(this, _parentPropertyGrid);
        }
    }
 
    /// <summary>
    /// Represents the PropertyGridToolStrip control accessibility object.
    /// </summary>
    [ComVisible(true)]
    internal class PropertyGridToolStripAccessibleObject : ToolStrip.ToolStripAccessibleObject {
 
        private PropertyGrid _parentPropertyGrid;
 
        /// <summary>
        /// Constructs new instance of PropertyGridToolStripAccessibleObject
        /// </summary>
        /// <param name="owningPropertyGridToolStrip">The PropertyGridToolStrip owning control.</param>
        /// <param name="parentPropertyGrid">The parent PropertyGrid control.</param>
        public PropertyGridToolStripAccessibleObject(PropertyGridToolStrip owningPropertyGridToolStrip, PropertyGrid parentPropertyGrid) : base(owningPropertyGridToolStrip) {
            _parentPropertyGrid = parentPropertyGrid;
        }
 
        /// <summary>
        /// Request to return the element in the specified direction.
        /// </summary>
        /// <param name="direction">Indicates the direction in which to navigate.</param>
        /// <returns>Returns the element in the specified direction.</returns>
        internal override UnsafeNativeMethods.IRawElementProviderFragment FragmentNavigate(UnsafeNativeMethods.NavigateDirection direction) {
            var propertyGridAccessibleObject = _parentPropertyGrid.AccessibilityObject as PropertyGridAccessibleObject;
            if (propertyGridAccessibleObject != null) {
                var navigationTarget = propertyGridAccessibleObject.ChildFragmentNavigate(this, direction);
                if (navigationTarget != null) {
                    return navigationTarget;
                }
            }
 
            return base.FragmentNavigate(direction);
        }
 
        /// <summary>
        /// Request value of specified property from an element.
        /// </summary>
        /// <param name="propertyId">Identifier indicating the property to return</param>
        /// <returns>Returns a ValInfo indicating whether the element supports this property, or has no value for it.</returns>
        internal override object GetPropertyValue(int propertyID) {
            if (propertyID == NativeMethods.UIA_ControlTypePropertyId) {
                return NativeMethods.UIA_ToolBarControlTypeId;
            } else if (propertyID == NativeMethods.UIA_NamePropertyId) {
                return Name;
            }
 
            return base.GetPropertyValue(propertyID);
        }
    }
}