PropertyGrid.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyGrid.cs / 3 / PropertyGrid.cs

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

namespace System.Windows.Forms { 
 
    using Microsoft.Win32;
    using System; 
    using System.Security.Permissions;
    using System.IO;
    using System.Collections;
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Drawing.Imaging;
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Windows.Forms;
    using System.Windows.Forms.ComponentModel.Com2Interop; 
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.PropertyGridInternal;
    using System.ComponentModel.Design.Serialization; 

    /// 
    /// 
    ///    [To be supplied.] 
    /// 
    [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 = SystemColors.InactiveBorder; 
        private Color   categoryForeColor = SystemColors.ControlText;
        internal Brush  lineBrush = null; 
 
        private AttributeCollection browsableAttributes;
 
        private SnappableControl                    targetMove = null;
        private int                                 dividerMoveY = -1;
        private const int                    CYDIVIDER = 3;
        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 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();
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [ 
            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;

            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 = 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;

                // 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); 
                }
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override bool AutoScroll {
            get {
                return base.AutoScroll; 
            }
            set { 
                base.AutoScroll = value; 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public override Color BackColor { 
            get { 
                return base.BackColor;
            } 
            set {
                base.BackColor = value;
                toolStrip.BackColor = value;
                toolStrip.Invalidate(true); 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage { 
            get {
                return base.BackgroundImage; 
            } 
            set {
                base.BackgroundImage = value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler BackgroundImageChanged { 
            add {
                base.BackgroundImageChanged += value; 
            }
            remove {
                base.BackgroundImageChanged -= value;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout {
            get { 
                return base.BackgroundImageLayout;
            } 
            set { 
                base.BackgroundImageLayout = value;
            } 
        }

        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged { 
            add { 
                base.BackgroundImageLayoutChanged += value;
            } 
            remove {
                base.BackgroundImageLayoutChanged -= value;
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        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;
            } 
        } 

        ///  
        /// 
        /// true if the commands pane will be can be made visible
        /// for the currently selected objects.  Objects that
        /// expose verbs can show commands. 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), 
         SRDescription(SR.PropertyGridCanShowCommandsDesc)] 
        public virtual bool CanShowCommands {
            get { 
                return hotcommands.WouldBeVisible;
            }
        }
 
        /// 
        ///  
        /// The text used color for category headings. The background color is determined by the LineColor property. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCategoryForeColorDesc),
        DefaultValue(typeof(Color), "ControlText")
        ] 
        public Color CategoryForeColor {
            get { 
                return categoryForeColor; 
            }
            set { 
                if (categoryForeColor != value) {
                    categoryForeColor = value;
                    gridView.Invalidate();
                } 
            }
        } 
 
        /// 
        ///  
        /// The background color for the hot commands region.
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridCommandsBackColorDesc)
        ] 
        public Color CommandsBackColor { 
            get {
                return hotcommands.BackColor; 
            }
            set {
                hotcommands.BackColor = value;
            } 
        }
 
        ///  
        /// 
        /// The forground color for the hot commands region. 
        /// 
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsForeColorDesc) 
        ]
        public Color CommandsForeColor { 
            get { 
                return hotcommands.ForeColor;
            } 
            set {
                hotcommands.ForeColor = value;
            }
        } 

        ///  
        ///  
        /// The link color for the hot commands region.
        ///  
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsLinkColorDesc)
        ] 
        public Color CommandsLinkColor {
            get { 
                return hotcommands.Label.LinkColor; 
            }
            set { 
                hotcommands.Label.LinkColor = value;
            }
        }
 
        /// 
        ///  
        /// The active link color for the hot commands region. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsActiveLinkColorDesc)
        ]
        public Color CommandsActiveLinkColor { 
            get {
                return hotcommands.Label.ActiveLinkColor; 
            } 
            set {
                hotcommands.Label.ActiveLinkColor = value; 
            }
        }

        ///  
        /// 
        /// The color for the hot commands region when the link is disabled. 
        ///  
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridCommandsDisabledLinkColorDesc)
        ]
        public Color CommandsDisabledLinkColor {
            get { 
                return hotcommands.Label.DisabledLinkColor;
            } 
            set { 
                hotcommands.Label.DisabledLinkColor = value;
            } 
        }

        /// 
        ///  
        /// Returns true if the commands pane is currently shown.
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public virtual bool CommandsVisible {
            get { 
                return hotcommands.Visible;
            }
        }
 
        /// 
        ///  
        /// Returns true if the commands pane will be shown for objects 
        /// that expose verbs.
        ///  
        [
        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(); 
                }
            } 
        }

        /// 
        ///  
        /// 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.
        ///  
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public Point ContextMenuDefaultLocation {
            get { 
                return GetPropertyGridView().ContextMenuDefaultLocation; 
            }
        } 

         /// 
         /// 
        ///     Collection of child controls. 
        /// 
        [ 
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public new ControlCollection Controls {
            get {
                return base.Controls;
            } 
        }
 
 
        /// 
        protected override Size DefaultSize { 
            get {
                return new Size(130, 130);
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        protected virtual Type DefaultTabType {
            get { 
               return typeof(PropertiesTab); 
            }
        } 

        /// 
        ///
        protected bool DrawFlatToolbar { 
            get {
                return drawFlatToolBar; 
            } 
            set {
                if (drawFlatToolBar != value) { 
                    drawFlatToolBar = value;
                    SetToolStripRenderer();
                }
 
                SetHotCommandColors(value);
            } 
        } 

        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Color ForeColor {
            get {
                return base.ForeColor; 
            }
            set { 
                base.ForeColor = value; 
            }
        } 

        /// 
        /// 
        [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);
                  } 
 
               }
            } 
        }

        /// 
        ///  
        /// The background color for the help region.
        ///  
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpBackColorDesc), 
        DefaultValue(typeof(Color), "Control")
        ]
        public Color HelpBackColor {
            get { 
                return doccomment.BackColor;
            } 
            set { 
                doccomment.BackColor = value;
            } 
        }

        /// 
        ///  
        /// The forground color for the help region.
        ///  
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpForeColorDesc), 
        DefaultValue(typeof(Color), "ControlText")
        ]
        public Color HelpForeColor {
            get { 
                return doccomment.ForeColor;
            } 
            set { 
                doccomment.ForeColor = value;
            } 
        }

        /// 
        ///  
        /// Sets or gets the visiblity state of the help pane.
        ///  
        [ 
        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();
            } 
        } 

        ///  
        /// 
        bool IComPropertyBrowser.InPropertySet {
            get {
                return GetPropertyGridView().GetInPropertySet(); 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridLineColorDesc),
        DefaultValue(typeof(Color), "InactiveBorder") 
        ] 
        public Color LineColor {
            get { 
                return lineColor;
            }
            set {
                if (lineColor != value) { 
                    lineColor = value;
                    if (lineBrush != null) { 
                        lineBrush.Dispose(); 
                        lineBrush = null;
                    } 
                    gridView.Invalidate();
                }
            }
        } 

        ///  
        ///  
        ///    
        ///    [To be supplied.] 
        ///    
        /// 
        [
        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; }
        }

        ///  
        /// 
        /// Sets or gets the current property sort type, which can be 
        /// PropertySort.Categorized or PropertySort.Alphabetical. 
        /// 
        [ 
        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.
                    } 
                } 

            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [ 
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public PropertyTabCollection PropertyTabs {
            get {
                return new PropertyTabCollection(this); 
            }
        } 
 
        /// 
        ///  
        /// 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.
        ///  
        [
        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};
                } 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [
        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(); 
                        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) {
                            gridView.RemoveSelectedEntryHelpAttributes();
                        } 

                        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); 
                    }
 
 
                    /*
 
                    [....], 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();
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        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];
            } 
        }


 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [ 
        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; 
            }
        } 
 
        /// 
        /// 
        protected internal override bool ShowFocusCues {
            get {
                return true;
            } 
        }
 
        ///  
        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); 

            }
        }
 
        [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; 
            }
        } 
 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [ 
        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(); 
            }
        } 

        /// 
        /// 
        /// Sets or gets the visiblity state of the toolStrip. 
        /// 
        [ 
        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;
                } 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridViewBackColorDesc),
        DefaultValue(typeof(Color), "Window") 
        ] 
        public Color ViewBackColor {
            get { 
                return gridView.BackColor;
            }
            set {
                gridView.BackColor = value; 
                gridView.Invalidate();
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
                [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridViewForeColorDesc), 
        DefaultValue(typeof(Color), "WindowText") 
        ]
        public Color ViewForeColor { 
            get {
                return gridView.ForeColor;
            }
            set { 
                gridView.ForeColor = value;
                gridView.Invalidate(); 
 
            }
        } 

        private int AddImage(Bitmap image) {

            image.MakeTransparent(); 

            int result = imageList[NORMAL_BUTTONS].Images.Count; 
            imageList[NORMAL_BUTTONS].Images.Add(image); 
            return result;
        } 

        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event KeyEventHandler KeyDown {
            add { 
                base.KeyDown += value; 
            }
            remove { 
                base.KeyDown -= value;
            }
        }
 

        ///  
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyPressEventHandler KeyPress { 
            add {
                base.KeyPress += value;
            }
            remove { 
                base.KeyPress -= value;
            } 
        } 

 
        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyEventHandler KeyUp { 
            add {
                base.KeyUp += value; 
            } 
            remove {
                base.KeyUp -= value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event MouseEventHandler MouseDown { 
            add {
                base.MouseDown += value; 
            }
            remove {
                base.MouseDown -= value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event MouseEventHandler MouseUp {
            add {
                base.MouseUp += value;
            } 
            remove {
                base.MouseUp -= value; 
            } 
        }
 
        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event MouseEventHandler MouseMove { 
            add {
                base.MouseMove += value; 
            } 
            remove {
                base.MouseMove -= value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event EventHandler MouseEnter { 
            add {
                base.MouseEnter += value; 
            }
            remove {
                base.MouseEnter -= value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event EventHandler MouseLeave {
            add {
                base.MouseLeave += value;
            } 
            remove {
                base.MouseLeave -= value; 
            } 
        }
 
        /// 
        ///  Event that is fired when a property value is modified.
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyValueChangedDescr)]
        public event PropertyValueChangedEventHandler PropertyValueChanged { 
            add {
                Events.AddHandler(EventPropertyValueChanged, value); 
            } 
            remove {
                Events.RemoveHandler(EventPropertyValueChanged, value); 
            }
        }

        ///  
        ///
        event ComponentRenameEventHandler IComPropertyBrowser.ComComponentNameChanged { 
            add { 
                Events.AddHandler(EventComComponentNameChanged, value);
            } 
            remove {
                Events.RemoveHandler(EventComComponentNameChanged, value);
            }
        } 

        ///  
        ///  Event that is fired when the current view tab is changed, such as changing from Properties to Events 
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyTabchangedDescr)]
        public event PropertyTabChangedEventHandler PropertyTabChanged { 
            add {
                Events.AddHandler(EventPropertyTabChanged, value);
            }
            remove { 
                Events.RemoveHandler(EventPropertyTabChanged, value);
            } 
        } 

        ///  
        ///  Event that is fired when the sort mode is changed.
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertySortChangedDescr)]
        public event EventHandler PropertySortChanged {
            add { 
                Events.AddHandler(EventPropertySortChanged, value);
            } 
            remove { 
                Events.RemoveHandler(EventPropertySortChanged, value);
            } 
        }

        /// 
        ///  Event that is fired when the selected GridItem is changed 
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridSelectedGridItemChangedDescr)]
        public event SelectedGridItemChangedEventHandler SelectedGridItemChanged { 
            add { 
                Events.AddHandler(EventSelectedGridItemChanged, value);
            } 
            remove {
                Events.RemoveHandler(EventSelectedGridItemChanged, value);
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [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);
            } 
        }
 
        ///  
        ///  Collapses all the nodes in the PropertyGrid
        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();
            } 
        }
 
 
        /// 
        /// Clears the tabs of the given scope or smaller. 
        /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
        /// 
        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
 
        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();
            return button;
        } 

        ///  
        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) {
            ToolStripButton button = new ToolStripButton(); 
            button.Text = toolTipText;
            button.AutoToolTip = true;
            button.DisplayStyle = ToolStripItemDisplayStyle.Image;
            button.ImageIndex = imageIndex; 
            button.Click += eventHandler;
            button.ImageScaling = ToolStripItemImageScaling.SizeToFit; 
            return button; 
        }
 
        ///
        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);
                }
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        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);
                }
            } 
        }
 
        ///  
        /// 
        ///  
        /// [To be supplied.]
        /// 
        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 = new Size(32,32);
 
                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], 32,32));
                    }
                } 
            }
        } 
 
        /// 
        ///  
        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);
                }
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        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; 
        }
 
        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;
        } 

 
        ///  
        /// 
        void IComPropertyBrowser.HandleF4() { 

            if (gridView.ContainsFocus) {
                return;
            } 

            if (this.ActiveControl != gridView) { 
                this.SetActiveControlInternal(gridView); 
            }
            gridView.FocusInternal(); 
        }

        internal bool HavePropEntriesChanged() {
            return GetFlag(PropertiesChanged); 
        }
 
 
        /// 
        ///  
        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; 
            }
        } 

        /// 
        /// 
        ///  
        /// Called when a property on an Ole32 Object changes.
        /// See IPropertyNotifySink::OnChanged 
        ///  
        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))); 
                }
            }
        }
 
        /// 
        /// We forward messages from several of our children 
        /// to our mouse move so we can put up the spliter over their borders 
        /// 
        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;
            } 
        } 

        ///  
        /// We forward messages from several of our children
        /// to our mouse move so we can put up the spliter over their borders
        /// 
        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) { 
                            Array.Copy(currentObjects, 0, newObjects, i + 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(); 
 
        }
 
        /// 
        [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(); 
        } 

        ///  
        [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();
       } 
 
        /// 
        ///  
        internal void OnGridViewMouseWheel(MouseEventArgs e) {
            this.OnMouseWheel(e);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [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); 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [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);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  

        [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); 
                }
            } 
        } 

        ///  
        [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) ?  41 : 25; 
                        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; 
            }
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  

        [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);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
 
        [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); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 

        [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); 
        }
 
        /// 
        /// 
        /// 
        /// Called when a property on an Ole32 Object that is tagged 
        /// with "requestedit" is about to be edited.
        /// See IPropertyNotifySink::OnRequestEdit 
        ///  
        int UnsafeNativeMethods.IPropertyNotifySink.OnRequestEdit(int dispID) {
            // we don't do anything here... 
            return NativeMethods.S_OK;
        }

        ///  

        [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();
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [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);
        } 
 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        // 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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        // 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;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        // 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); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        // 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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        // 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));
        } 
 
        internal void OnSelectedGridItemChanged(GridEntry oldEntry, GridEntry newEntry) {
            OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs(oldEntry, newEntry)); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
 
        [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);
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
 
        [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); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
 
        [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();
            }
        } 

        /* 
 
        /// 
        /// Returns the first child control that can take focus 
        /// 
        /// 
        /// Returns null if no control is able to take focus
        ///  
        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;
 
         } 
        }
        */ 

        /// 
        /// 
        /// Returns the last child control that can take focus 
        /// 
        [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();
                            } 
                            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);
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        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();
        } 
 

        ///  
        /// 
        /// Refreshes the tabs of the given scope by deleting them and requerying objects and documents
        /// for them.
        ///  
        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;
                }
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        public void ResetSelectedProperty() {
            GetPropertyGridView().Reset();
        } 

        private void SaveTabSelection() { 
            if (designerHost != null) { 
               if (designerSelections == null) {
                   designerSelections = new Hashtable(); 
               }
               designerSelections[designerHost.GetHashCode()] = selectedViewTab;
            }
        } 

        ///  
        ///  
        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) {
                // 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(); 
               }

               // 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 = new Bitmap(typeof(PropertyGrid), "PBAlpha.bmp"); 
                       } 
                       alphaIndex = AddImage(bmpAlpha);
                   } 
                   catch (Exception e)
                   {
                       Debug.Fail("Failed to load Alpha bitmap", e.ToString());
                   } 

                   try { 
                       if (bmpCategory == null) { 
                           bmpCategory = new Bitmap(typeof(PropertyGrid), "PBCatego.bmp");
                       } 
                       categoryIndex = AddImage(bmpCategory);
                   }
                   catch (Exception e)
                   { 
                       Debug.Fail("Failed to load category bitmap", e.ToString());
                   } 
 
                   viewSortButtons[ALPHA] = CreatePushButton(SR.GetString(SR.PBRSToolTipAlphabetic), alphaIndex, ehViewType);
                   viewSortButtons[CATEGORIES] = CreatePushButton(SR.GetString(SR.PBRSToolTipCategorized), categoryIndex, ehViewType); 

                   // we create a dummy hidden button for view sort
                   viewSortButtons[NO_SORT] = CreatePushButton("", 0, ehViewType);
                   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);
                       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 = new Bitmap(typeof(PropertyGrid), "PBPPage.bmp"); 
                   }
                   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);
               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;
           } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        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();
        } 

        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();
        }

        ///  
        ///  Sinks the property notify events on all the objects we are currently
        ///  browsing. 
        /// 
        ///  See IPropertyNotifySink
        ///  
        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();
        } 
 
        /// 
        ///     Determines whether to use compatible text rendering engine (GDI+) or not (GDI). 
        /// 
        [
        DefaultValue(false),
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.UseCompatibleTextRenderingDescr)
        ] 
        public bool UseCompatibleTextRendering { 
            get{
                return base.UseCompatibleTextRenderingInt; 
            }
            set{
                base.UseCompatibleTextRenderingInt = value;
                doccomment.UpdateTextRenderingEngine(); 
                gridView.Invalidate();
            } 
        } 

        ///  
        ///     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.
        ///  
        internal override bool SupportsUseCompatibleTextRendering {
            get { 
                return true; 
            }
        } 

        // 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;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 

        [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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
 
        // 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 { 
            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; 
                }
            }
            */
 
            protected override void OnPaint(PaintEventArgs e) {
                base.OnPaint(e); 
                Rectangle r = this.ClientRectangle; 
                r.Width --;
                r.Height--; 
                e.Graphics.DrawRectangle(SystemPens.ControlDark, r);
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [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 {

            ///  
            ///    [To be supplied.]
            ///  
            internal static PropertyTabCollection Empty = new PropertyTabCollection(null); 

            private  PropertyGrid   owner; 

            internal PropertyTabCollection(PropertyGrid owner) {
                this.owner = owner;
            } 

            ///  
            ///  
            ///     Retrieves the number of member attributes.
            ///  
            public int Count {
                get {
                    if (owner == null) {
                        return 0; 
                    }
                    return owner.viewTabs.Length; 
                } 
            }
 
            /// 
            /// 
            object ICollection.SyncRoot {
                get { 
                    return this;
                } 
            } 

            ///  
            /// 
            bool ICollection.IsSynchronized {
                get {
                    return false; 
                }
            } 
 
            /// 
            ///  
            ///     Retrieves the member attribute with the specified index.
            /// 
            public PropertyTab this[int index] {
                get { 
                    if (owner == null) {
                        throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly)); 
                    } 
                    return owner.viewTabs[index];
                } 
            }

            /// 
            ///  
            ///    [To be supplied.]
            ///  
            public void AddTabType(Type propertyTabType) { 
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly)); 
                }
                owner.AddTab(propertyTabType, PropertyTabScope.Global);
            }
 
            /// 
            ///  
            ///    [To be supplied.] 
            /// 
            public void AddTabType(Type propertyTabType, PropertyTabScope tabScope) { 
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.AddTab(propertyTabType, tabScope); 
            }
 
            ///  
            /// 
            /// Clears the tabs of the given scope or smaller. 
            /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
            /// 
            public void Clear(PropertyTabScope tabScope) {
                if (owner == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                } 
                owner.ClearTabs(tabScope); 
            }
 

            /// 
            /// 
            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); 
                }
            }
            /// 
            ///  
            ///      Creates and retrieves a new enumerator for this collection.
            ///  
            public IEnumerator GetEnumerator() { 
                if (owner == null) {
                    return new PropertyTab[0].GetEnumerator(); 
                }

                return owner.viewTabs.GetEnumerator();
            } 

            ///  
            ///  
            ///    [To be supplied.]
            ///  
            public void RemoveTabType(Type propertyTabType) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                } 
                owner.RemoveTab(propertyTabType);
            } 
 
        }
 
        /// 
        ///     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. 
        ///  
        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;
            }
        }
 
        /// 
        ///     Helper class to support rendering text using either GDI or GDI+. 
        ///  
        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;

        ///  
        ///     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.
        ///  
        [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;
        } 
 
        /// 
        ///     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.
        /// 
        [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; 
        } 

        ///  
        ///     Generate log file from id.
        /// 
        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;
        } 
    }
 
} 


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

namespace System.Windows.Forms { 
 
    using Microsoft.Win32;
    using System; 
    using System.Security.Permissions;
    using System.IO;
    using System.Collections;
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
    using System.Drawing; 
    using System.Drawing.Design;
    using System.Drawing.Imaging;
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Windows.Forms;
    using System.Windows.Forms.ComponentModel.Com2Interop; 
    using System.Windows.Forms.Design; 
    using System.Windows.Forms.PropertyGridInternal;
    using System.ComponentModel.Design.Serialization; 

    /// 
    /// 
    ///    [To be supplied.] 
    /// 
    [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 = SystemColors.InactiveBorder; 
        private Color   categoryForeColor = SystemColors.ControlText;
        internal Brush  lineBrush = null; 
 
        private AttributeCollection browsableAttributes;
 
        private SnappableControl                    targetMove = null;
        private int                                 dividerMoveY = -1;
        private const int                    CYDIVIDER = 3;
        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 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();
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [ 
            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;

            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 = 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;

                // 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); 
                }
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override bool AutoScroll {
            get {
                return base.AutoScroll; 
            }
            set { 
                base.AutoScroll = value; 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public override Color BackColor { 
            get { 
                return base.BackColor;
            } 
            set {
                base.BackColor = value;
                toolStrip.BackColor = value;
                toolStrip.Invalidate(true); 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage { 
            get {
                return base.BackgroundImage; 
            } 
            set {
                base.BackgroundImage = value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler BackgroundImageChanged { 
            add {
                base.BackgroundImageChanged += value; 
            }
            remove {
                base.BackgroundImageChanged -= value;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override ImageLayout BackgroundImageLayout {
            get { 
                return base.BackgroundImageLayout;
            } 
            set { 
                base.BackgroundImageLayout = value;
            } 
        }

        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged { 
            add { 
                base.BackgroundImageLayoutChanged += value;
            } 
            remove {
                base.BackgroundImageLayoutChanged -= value;
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        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;
            } 
        } 

        ///  
        /// 
        /// true if the commands pane will be can be made visible
        /// for the currently selected objects.  Objects that
        /// expose verbs can show commands. 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), 
         SRDescription(SR.PropertyGridCanShowCommandsDesc)] 
        public virtual bool CanShowCommands {
            get { 
                return hotcommands.WouldBeVisible;
            }
        }
 
        /// 
        ///  
        /// The text used color for category headings. The background color is determined by the LineColor property. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCategoryForeColorDesc),
        DefaultValue(typeof(Color), "ControlText")
        ] 
        public Color CategoryForeColor {
            get { 
                return categoryForeColor; 
            }
            set { 
                if (categoryForeColor != value) {
                    categoryForeColor = value;
                    gridView.Invalidate();
                } 
            }
        } 
 
        /// 
        ///  
        /// The background color for the hot commands region.
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridCommandsBackColorDesc)
        ] 
        public Color CommandsBackColor { 
            get {
                return hotcommands.BackColor; 
            }
            set {
                hotcommands.BackColor = value;
            } 
        }
 
        ///  
        /// 
        /// The forground color for the hot commands region. 
        /// 
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsForeColorDesc) 
        ]
        public Color CommandsForeColor { 
            get { 
                return hotcommands.ForeColor;
            } 
            set {
                hotcommands.ForeColor = value;
            }
        } 

        ///  
        ///  
        /// The link color for the hot commands region.
        ///  
        [
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsLinkColorDesc)
        ] 
        public Color CommandsLinkColor {
            get { 
                return hotcommands.Label.LinkColor; 
            }
            set { 
                hotcommands.Label.LinkColor = value;
            }
        }
 
        /// 
        ///  
        /// The active link color for the hot commands region. 
        /// 
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridCommandsActiveLinkColorDesc)
        ]
        public Color CommandsActiveLinkColor { 
            get {
                return hotcommands.Label.ActiveLinkColor; 
            } 
            set {
                hotcommands.Label.ActiveLinkColor = value; 
            }
        }

        ///  
        /// 
        /// The color for the hot commands region when the link is disabled. 
        ///  
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridCommandsDisabledLinkColorDesc)
        ]
        public Color CommandsDisabledLinkColor {
            get { 
                return hotcommands.Label.DisabledLinkColor;
            } 
            set { 
                hotcommands.Label.DisabledLinkColor = value;
            } 
        }

        /// 
        ///  
        /// Returns true if the commands pane is currently shown.
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public virtual bool CommandsVisible {
            get { 
                return hotcommands.Visible;
            }
        }
 
        /// 
        ///  
        /// Returns true if the commands pane will be shown for objects 
        /// that expose verbs.
        ///  
        [
        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(); 
                }
            } 
        }

        /// 
        ///  
        /// 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.
        ///  
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public Point ContextMenuDefaultLocation {
            get { 
                return GetPropertyGridView().ContextMenuDefaultLocation; 
            }
        } 

         /// 
         /// 
        ///     Collection of child controls. 
        /// 
        [ 
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public new ControlCollection Controls {
            get {
                return base.Controls;
            } 
        }
 
 
        /// 
        protected override Size DefaultSize { 
            get {
                return new Size(130, 130);
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        protected virtual Type DefaultTabType {
            get { 
               return typeof(PropertiesTab); 
            }
        } 

        /// 
        ///
        protected bool DrawFlatToolbar { 
            get {
                return drawFlatToolBar; 
            } 
            set {
                if (drawFlatToolBar != value) { 
                    drawFlatToolBar = value;
                    SetToolStripRenderer();
                }
 
                SetHotCommandColors(value);
            } 
        } 

        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Color ForeColor {
            get {
                return base.ForeColor; 
            }
            set { 
                base.ForeColor = value; 
            }
        } 

        /// 
        /// 
        [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);
                  } 
 
               }
            } 
        }

        /// 
        ///  
        /// The background color for the help region.
        ///  
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpBackColorDesc), 
        DefaultValue(typeof(Color), "Control")
        ]
        public Color HelpBackColor {
            get { 
                return doccomment.BackColor;
            } 
            set { 
                doccomment.BackColor = value;
            } 
        }

        /// 
        ///  
        /// The forground color for the help region.
        ///  
        [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridHelpForeColorDesc), 
        DefaultValue(typeof(Color), "ControlText")
        ]
        public Color HelpForeColor {
            get { 
                return doccomment.ForeColor;
            } 
            set { 
                doccomment.ForeColor = value;
            } 
        }

        /// 
        ///  
        /// Sets or gets the visiblity state of the help pane.
        ///  
        [ 
        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();
            } 
        } 

        ///  
        /// 
        bool IComPropertyBrowser.InPropertySet {
            get {
                return GetPropertyGridView().GetInPropertySet(); 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridLineColorDesc),
        DefaultValue(typeof(Color), "InactiveBorder") 
        ] 
        public Color LineColor {
            get { 
                return lineColor;
            }
            set {
                if (lineColor != value) { 
                    lineColor = value;
                    if (lineBrush != null) { 
                        lineBrush.Dispose(); 
                        lineBrush = null;
                    } 
                    gridView.Invalidate();
                }
            }
        } 

        ///  
        ///  
        ///    
        ///    [To be supplied.] 
        ///    
        /// 
        [
        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; }
        }

        ///  
        /// 
        /// Sets or gets the current property sort type, which can be 
        /// PropertySort.Categorized or PropertySort.Alphabetical. 
        /// 
        [ 
        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.
                    } 
                } 

            } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        [ 
        Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public PropertyTabCollection PropertyTabs {
            get {
                return new PropertyTabCollection(this); 
            }
        } 
 
        /// 
        ///  
        /// 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.
        ///  
        [
        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};
                } 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [
        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(); 
                        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) {
                            gridView.RemoveSelectedEntryHelpAttributes();
                        } 

                        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); 
                    }
 
 
                    /*
 
                    [....], 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();
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [
        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];
            } 
        }


 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [ 
        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; 
            }
        } 
 
        /// 
        /// 
        protected internal override bool ShowFocusCues {
            get {
                return true;
            } 
        }
 
        ///  
        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); 

            }
        }
 
        [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; 
            }
        } 
 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [ 
        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(); 
            }
        } 

        /// 
        /// 
        /// Sets or gets the visiblity state of the toolStrip. 
        /// 
        [ 
        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;
                } 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.PropertyGridViewBackColorDesc),
        DefaultValue(typeof(Color), "Window") 
        ] 
        public Color ViewBackColor {
            get { 
                return gridView.BackColor;
            }
            set {
                gridView.BackColor = value; 
                gridView.Invalidate();
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
                [ 
        SRCategory(SR.CatAppearance),
        SRDescription(SR.PropertyGridViewForeColorDesc), 
        DefaultValue(typeof(Color), "WindowText") 
        ]
        public Color ViewForeColor { 
            get {
                return gridView.ForeColor;
            }
            set { 
                gridView.ForeColor = value;
                gridView.Invalidate(); 
 
            }
        } 

        private int AddImage(Bitmap image) {

            image.MakeTransparent(); 

            int result = imageList[NORMAL_BUTTONS].Images.Count; 
            imageList[NORMAL_BUTTONS].Images.Add(image); 
            return result;
        } 

        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event KeyEventHandler KeyDown {
            add { 
                base.KeyDown += value; 
            }
            remove { 
                base.KeyDown -= value;
            }
        }
 

        ///  
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyPressEventHandler KeyPress { 
            add {
                base.KeyPress += value;
            }
            remove { 
                base.KeyPress -= value;
            } 
        } 

 
        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event KeyEventHandler KeyUp { 
            add {
                base.KeyUp += value; 
            } 
            remove {
                base.KeyUp -= value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event MouseEventHandler MouseDown { 
            add {
                base.MouseDown += value; 
            }
            remove {
                base.MouseDown -= value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event MouseEventHandler MouseUp {
            add {
                base.MouseUp += value;
            } 
            remove {
                base.MouseUp -= value; 
            } 
        }
 
        /// 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public new event MouseEventHandler MouseMove { 
            add {
                base.MouseMove += value; 
            } 
            remove {
                base.MouseMove -= value; 
            }
        }

        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event EventHandler MouseEnter { 
            add {
                base.MouseEnter += value; 
            }
            remove {
                base.MouseEnter -= value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public new event EventHandler MouseLeave {
            add {
                base.MouseLeave += value;
            } 
            remove {
                base.MouseLeave -= value; 
            } 
        }
 
        /// 
        ///  Event that is fired when a property value is modified.
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyValueChangedDescr)]
        public event PropertyValueChangedEventHandler PropertyValueChanged { 
            add {
                Events.AddHandler(EventPropertyValueChanged, value); 
            } 
            remove {
                Events.RemoveHandler(EventPropertyValueChanged, value); 
            }
        }

        ///  
        ///
        event ComponentRenameEventHandler IComPropertyBrowser.ComComponentNameChanged { 
            add { 
                Events.AddHandler(EventComComponentNameChanged, value);
            } 
            remove {
                Events.RemoveHandler(EventComComponentNameChanged, value);
            }
        } 

        ///  
        ///  Event that is fired when the current view tab is changed, such as changing from Properties to Events 
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertyTabchangedDescr)]
        public event PropertyTabChangedEventHandler PropertyTabChanged { 
            add {
                Events.AddHandler(EventPropertyTabChanged, value);
            }
            remove { 
                Events.RemoveHandler(EventPropertyTabChanged, value);
            } 
        } 

        ///  
        ///  Event that is fired when the sort mode is changed.
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridPropertySortChangedDescr)]
        public event EventHandler PropertySortChanged {
            add { 
                Events.AddHandler(EventPropertySortChanged, value);
            } 
            remove { 
                Events.RemoveHandler(EventPropertySortChanged, value);
            } 
        }

        /// 
        ///  Event that is fired when the selected GridItem is changed 
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.PropertyGridSelectedGridItemChangedDescr)]
        public event SelectedGridItemChangedEventHandler SelectedGridItemChanged { 
            add { 
                Events.AddHandler(EventSelectedGridItemChanged, value);
            } 
            remove {
                Events.RemoveHandler(EventSelectedGridItemChanged, value);
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [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);
            } 
        }
 
        ///  
        ///  Collapses all the nodes in the PropertyGrid
        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();
            } 
        }
 
 
        /// 
        /// Clears the tabs of the given scope or smaller. 
        /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
        /// 
        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
 
        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();
            return button;
        } 

        ///  
        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) {
            ToolStripButton button = new ToolStripButton(); 
            button.Text = toolTipText;
            button.AutoToolTip = true;
            button.DisplayStyle = ToolStripItemDisplayStyle.Image;
            button.ImageIndex = imageIndex; 
            button.Click += eventHandler;
            button.ImageScaling = ToolStripItemImageScaling.SizeToFit; 
            return button; 
        }
 
        ///
        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);
                }
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        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);
                }
            } 
        }
 
        ///  
        /// 
        ///  
        /// [To be supplied.]
        /// 
        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 = new Size(32,32);
 
                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], 32,32));
                    }
                } 
            }
        } 
 
        /// 
        ///  
        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);
                }
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        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; 
        }
 
        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;
        } 

 
        ///  
        /// 
        void IComPropertyBrowser.HandleF4() { 

            if (gridView.ContainsFocus) {
                return;
            } 

            if (this.ActiveControl != gridView) { 
                this.SetActiveControlInternal(gridView); 
            }
            gridView.FocusInternal(); 
        }

        internal bool HavePropEntriesChanged() {
            return GetFlag(PropertiesChanged); 
        }
 
 
        /// 
        ///  
        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; 
            }
        } 

        /// 
        /// 
        ///  
        /// Called when a property on an Ole32 Object changes.
        /// See IPropertyNotifySink::OnChanged 
        ///  
        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))); 
                }
            }
        }
 
        /// 
        /// We forward messages from several of our children 
        /// to our mouse move so we can put up the spliter over their borders 
        /// 
        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;
            } 
        } 

        ///  
        /// We forward messages from several of our children
        /// to our mouse move so we can put up the spliter over their borders
        /// 
        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) { 
                            Array.Copy(currentObjects, 0, newObjects, i + 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(); 
 
        }
 
        /// 
        [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(); 
        } 

        ///  
        [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();
       } 
 
        /// 
        ///  
        internal void OnGridViewMouseWheel(MouseEventArgs e) {
            this.OnMouseWheel(e);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [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); 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [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);
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  

        [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); 
                }
            } 
        } 

        ///  
        [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) ?  41 : 25; 
                        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; 
            }
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  

        [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);
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
 
        [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); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 

        [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); 
        }
 
        /// 
        /// 
        /// 
        /// Called when a property on an Ole32 Object that is tagged 
        /// with "requestedit" is about to be edited.
        /// See IPropertyNotifySink::OnRequestEdit 
        ///  
        int UnsafeNativeMethods.IPropertyNotifySink.OnRequestEdit(int dispID) {
            // we don't do anything here... 
            return NativeMethods.S_OK;
        }

        ///  

        [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();
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [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);
        } 
 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        // 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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        // 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;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        // 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); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        // 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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        // 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));
        } 
 
        internal void OnSelectedGridItemChanged(GridEntry oldEntry, GridEntry newEntry) {
            OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs(oldEntry, newEntry)); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
 
        [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);
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
 
        [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); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
 
        [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();
            }
        } 

        /* 
 
        /// 
        /// Returns the first child control that can take focus 
        /// 
        /// 
        /// Returns null if no control is able to take focus
        ///  
        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;
 
         } 
        }
        */ 

        /// 
        /// 
        /// Returns the last child control that can take focus 
        /// 
        [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();
                            } 
                            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);
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        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();
        } 
 

        ///  
        /// 
        /// Refreshes the tabs of the given scope by deleting them and requerying objects and documents
        /// for them.
        ///  
        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;
                }
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        public void ResetSelectedProperty() {
            GetPropertyGridView().Reset();
        } 

        private void SaveTabSelection() { 
            if (designerHost != null) { 
               if (designerSelections == null) {
                   designerSelections = new Hashtable(); 
               }
               designerSelections[designerHost.GetHashCode()] = selectedViewTab;
            }
        } 

        ///  
        ///  
        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) {
                // 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(); 
               }

               // 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 = new Bitmap(typeof(PropertyGrid), "PBAlpha.bmp"); 
                       } 
                       alphaIndex = AddImage(bmpAlpha);
                   } 
                   catch (Exception e)
                   {
                       Debug.Fail("Failed to load Alpha bitmap", e.ToString());
                   } 

                   try { 
                       if (bmpCategory == null) { 
                           bmpCategory = new Bitmap(typeof(PropertyGrid), "PBCatego.bmp");
                       } 
                       categoryIndex = AddImage(bmpCategory);
                   }
                   catch (Exception e)
                   { 
                       Debug.Fail("Failed to load category bitmap", e.ToString());
                   } 
 
                   viewSortButtons[ALPHA] = CreatePushButton(SR.GetString(SR.PBRSToolTipAlphabetic), alphaIndex, ehViewType);
                   viewSortButtons[CATEGORIES] = CreatePushButton(SR.GetString(SR.PBRSToolTipCategorized), categoryIndex, ehViewType); 

                   // we create a dummy hidden button for view sort
                   viewSortButtons[NO_SORT] = CreatePushButton("", 0, ehViewType);
                   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);
                       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 = new Bitmap(typeof(PropertyGrid), "PBPPage.bmp"); 
                   }
                   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);
               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;
           } 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        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();
        } 

        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();
        }

        ///  
        ///  Sinks the property notify events on all the objects we are currently
        ///  browsing. 
        /// 
        ///  See IPropertyNotifySink
        ///  
        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();
        } 
 
        /// 
        ///     Determines whether to use compatible text rendering engine (GDI+) or not (GDI). 
        /// 
        [
        DefaultValue(false),
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.UseCompatibleTextRenderingDescr)
        ] 
        public bool UseCompatibleTextRendering { 
            get{
                return base.UseCompatibleTextRenderingInt; 
            }
            set{
                base.UseCompatibleTextRenderingInt = value;
                doccomment.UpdateTextRenderingEngine(); 
                gridView.Invalidate();
            } 
        } 

        ///  
        ///     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.
        ///  
        internal override bool SupportsUseCompatibleTextRendering {
            get { 
                return true; 
            }
        } 

        // 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;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 

        [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);
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
 
        // 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 { 
            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; 
                }
            }
            */
 
            protected override void OnPaint(PaintEventArgs e) {
                base.OnPaint(e); 
                Rectangle r = this.ClientRectangle; 
                r.Width --;
                r.Height--; 
                e.Graphics.DrawRectangle(SystemPens.ControlDark, r);
            }
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [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 {

            ///  
            ///    [To be supplied.]
            ///  
            internal static PropertyTabCollection Empty = new PropertyTabCollection(null); 

            private  PropertyGrid   owner; 

            internal PropertyTabCollection(PropertyGrid owner) {
                this.owner = owner;
            } 

            ///  
            ///  
            ///     Retrieves the number of member attributes.
            ///  
            public int Count {
                get {
                    if (owner == null) {
                        return 0; 
                    }
                    return owner.viewTabs.Length; 
                } 
            }
 
            /// 
            /// 
            object ICollection.SyncRoot {
                get { 
                    return this;
                } 
            } 

            ///  
            /// 
            bool ICollection.IsSynchronized {
                get {
                    return false; 
                }
            } 
 
            /// 
            ///  
            ///     Retrieves the member attribute with the specified index.
            /// 
            public PropertyTab this[int index] {
                get { 
                    if (owner == null) {
                        throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly)); 
                    } 
                    return owner.viewTabs[index];
                } 
            }

            /// 
            ///  
            ///    [To be supplied.]
            ///  
            public void AddTabType(Type propertyTabType) { 
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly)); 
                }
                owner.AddTab(propertyTabType, PropertyTabScope.Global);
            }
 
            /// 
            ///  
            ///    [To be supplied.] 
            /// 
            public void AddTabType(Type propertyTabType, PropertyTabScope tabScope) { 
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                }
                owner.AddTab(propertyTabType, tabScope); 
            }
 
            ///  
            /// 
            /// Clears the tabs of the given scope or smaller. 
            /// tabScope must be PropertyTabScope.Component or PropertyTabScope.Document.
            /// 
            public void Clear(PropertyTabScope tabScope) {
                if (owner == null) { 
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                } 
                owner.ClearTabs(tabScope); 
            }
 

            /// 
            /// 
            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); 
                }
            }
            /// 
            ///  
            ///      Creates and retrieves a new enumerator for this collection.
            ///  
            public IEnumerator GetEnumerator() { 
                if (owner == null) {
                    return new PropertyTab[0].GetEnumerator(); 
                }

                return owner.viewTabs.GetEnumerator();
            } 

            ///  
            ///  
            ///    [To be supplied.]
            ///  
            public void RemoveTabType(Type propertyTabType) {
                if (owner == null) {
                    throw new InvalidOperationException(SR.GetString(SR.PropertyGridPropertyTabCollectionReadOnly));
                } 
                owner.RemoveTab(propertyTabType);
            } 
 
        }
 
        /// 
        ///     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. 
        ///  
        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;
            }
        }
 
        /// 
        ///     Helper class to support rendering text using either GDI or GDI+. 
        ///  
        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;

        ///  
        ///     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.
        ///  
        [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;
        } 
 
        /// 
        ///     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.
        /// 
        [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; 
        } 

        ///  
        ///     Generate log file from id.
        /// 
        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;
        } 
    }
 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

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