PropertyGridView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyGridInternal / PropertyGridView.cs / 1555735 / PropertyGridView.cs

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

/* 
 */ 
namespace System.Windows.Forms.PropertyGridInternal {
    using System.Security.Permissions; 
    using System.Runtime.Serialization.Formatters;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting; 
    using System.Runtime.Versioning;
    using System.ComponentModel; 
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization; 
    using System;
    using System.Collections;
    using System.Windows.Forms;
    using System.Windows.Forms.Internal; 
    using System.Windows.Forms.ComponentModel;
    using System.Windows.Forms.Design; 
    using System.ComponentModel.Design; 
    using System.Windows.Forms.VisualStyles;
    using System.IO; 
    using System.Drawing;
    using System.Drawing.Design;
    using Microsoft.Win32;
    using Message = System.Windows.Forms.Message; 
    using System.Drawing.Drawing2D;
 
    internal class PropertyGridView : 
    Control,
    IWin32Window, 
    IWindowsFormsEditorService,
    IServiceProvider {

        protected static readonly Point InvalidPoint = new Point(int.MinValue, int.MinValue); 

#if true // RENDERMODE 
        public const int RENDERMODE_LEFTDOT = 2; 
        public const int RENDERMODE_BOLD = 3;
        public const int RENDERMODE_TRIANGLE = 4; 

        public static int inheritRenderMode = RENDERMODE_BOLD;
#endif
 

        public static TraceSwitch GridViewDebugPaint = new TraceSwitch("GridViewDebugPaint", "PropertyGridView: Debug property painting"); 
 

        private PropertyGrid ownerGrid;                      // the properties window host. 


#if true // RENDERMODE
        private const int LEFTDOT_SIZE = 4; 
#endif
        // constants 
        protected const int     EDIT_INDENT = 0; 
        protected const int     OUTLINE_INDENT = 10;
        protected const int     OUTLINE_SIZE = 9; 
        protected const int     OUTLINE_SIZE_EXPLORER_TREE_STYLE = 16;
        protected const int     PAINT_WIDTH = 20;
        protected const int     PAINT_INDENT = 26;
        protected const int     ROWLABEL = 1; 
        protected const int     ROWVALUE = 2;
        protected const int     MAX_LISTBOX_HEIGHT = 200; 
 
        protected const short    ERROR_NONE = 0;
        protected const short    ERROR_THROWN = 1; 
        protected const short    ERROR_MSGBOX_UP = 2;
        internal  const short    GDIPLUS_SPACE = 2;
        internal   const int      MaxRecurseExpand = 10;
 
        protected static readonly Point InvalidPosition = new Point(int.MinValue, int.MinValue);
 
 
        // colors and fonts
        private Brush                               backgroundBrush = null; 
        private   Font                              fontBold = null;

        // property collections
        private GridEntryCollection                 topLevelGridEntries = null;     // top level props 
        private GridEntryCollection                 allGridEntries = null;  // cache of viewable props
 
        // row information 
        internal  int                               totalProps = -1;        // # of viewable props
        private   int                               visibleRows = -1;         // # of visible rows 
        private   int                               labelWidth = -1;
        public double                               labelRatio = 2; // ratio of whole row to label width

        private short                               requiredLabelPaintMargin = GDIPLUS_SPACE; 

        // current selected row and tooltip. 
        private   int                               selectedRow = -1; 
        private GridEntry                           selectedGridEntry = null;
        private   int                               tipInfo = -1; 

        // editors & controls
        private   GridViewEdit                      edit = null;
        private   DropDownButton                    btnDropDown = null; 
        private   DropDownButton                    btnDialog = null;
        private   GridViewListBox                   listBox = null; 
        private   DropDownHolder                    dropDownHolder = null; 
        private   Rectangle                         lastClientRect = Rectangle.Empty;
        private   Control                           currentEditor = null; 
        private   ScrollBar                         scrollBar = null;
        internal  GridToolTip                       toolTip = null;
        private   GridErrorDlg                      errorDlg = null;
 

        // flags 
        private const short FlagNeedsRefresh            = 0x0001; 
        private const short FlagIsNewSelection          = 0x0002;
        private const short FlagIsSplitterMove          = 0x0004; 
        private const short FlagIsSpecialKey            = 0x0008;
        private const short FlagInPropertySet           = 0x0010;
        private const short FlagDropDownClosing         = 0x0020;
        private const short FlagDropDownCommit          = 0x0040; 
        private const short FlagNeedUpdateUIBasedOnFont = 0x0080;
        private const short FlagBtnLaunchedEditor       = 0x0100; 
        private const short FlagNoDefault               = 0x0200; 
        private const short FlagResizableDropDown       = 0x0400;
 

        private   short                             flags = FlagNeedsRefresh | FlagIsNewSelection | FlagNeedUpdateUIBasedOnFont;
        private   short                             errorState = ERROR_NONE;
 
        private   Point                             ptOurLocation = new Point(1,1);
 
        private   string                            originalTextValue = null;     // original text, in case of ESC 
        private   int                               cumulativeVerticalWheelDelta = 0;
        private   long                              rowSelectTime = 0; 
        private   Point                             rowSelectPos = Point.Empty; // the position that we clicked on a row to test for double clicks
        private   Point                             lastMouseDown = InvalidPosition;
        private   int                               lastMouseMove;
        private   GridEntry                         lastClickedEntry; 

        private IServiceProvider                    serviceProvider; 
        private IHelpService                        topHelpService; 
        private IHelpService                        helpService;
 
        private EventHandler                        ehValueClick;
        private EventHandler                        ehLabelClick;
        private EventHandler                        ehOutlineClick;
        private EventHandler                        ehValueDblClick; 
        private EventHandler                        ehLabelDblClick;
        private GridEntryRecreateChildrenEventHandler ehRecreateChildren; 
 
        private int                                 cachedRowHeight = -1;
        IntPtr baseHfont; 
        IntPtr boldHfont;


        [ 
            SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // PropertyGridView's caption is not visible.
                                                                                                        // So we don't have to localize its text. 
        ] 
        public PropertyGridView(IServiceProvider serviceProvider, PropertyGrid propertyGrid)
        : base() { 

            this.ehValueClick = new EventHandler(this.OnGridEntryValueClick);
            this.ehLabelClick = new EventHandler(this.OnGridEntryLabelClick);
            this.ehOutlineClick = new EventHandler(this.OnGridEntryOutlineClick); 
            this.ehValueDblClick = new EventHandler(this.OnGridEntryValueDoubleClick);
            this.ehLabelDblClick = new EventHandler(this.OnGridEntryLabelDoubleClick); 
            this.ehRecreateChildren = new GridEntryRecreateChildrenEventHandler(this.OnRecreateChildren); 

            ownerGrid = propertyGrid; 
            this.serviceProvider = serviceProvider;

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, false); 
            SetStyle(ControlStyles.UserMouse, true);
 
 
            // properties
            BackColor = SystemColors.Window; 
            ForeColor = SystemColors.WindowText;
            backgroundBrush = SystemBrushes.Window;
            TabStop = true;
 
            this.Text = "PropertyGridView";
 
            CreateUI(); 
            LayoutWindow(true);
        } 

        public override Color BackColor {
            get {
                return base.BackColor; 
            }
            set { 
                this.backgroundBrush = new SolidBrush(value); 
                base.BackColor = value;
            } 
        }

        internal Brush GetBackgroundBrush(Graphics g) {
            return backgroundBrush; 
        }
 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public bool CanCopy {
            get { 
                if (selectedGridEntry == null) {
                    return false;
                }
 
                if (!Edit.Focused) {
                    string val = selectedGridEntry.GetPropertyTextValue(); 
 
                    return val != null && val.Length > 0;
                } 

                return true;
            }
        } 

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public bool CanCut { 
            get {
                return CanCopy && selectedGridEntry.IsTextEditable; 
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] 
        public bool CanPaste {
            get { 
                return selectedGridEntry != null && selectedGridEntry.IsTextEditable; // return gridView.CanPaste; 
            }
        } 

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public bool CanUndo {
            get { 
                if (!Edit.Visible || !Edit.Focused) {
                    return false; 
                } 
                return (0 != (int)Edit.SendMessage(NativeMethods.EM_CANUNDO, 0, 0));
            } 
        }

        private DropDownButton DropDownButton {
            get { 
                if (btnDropDown == null) {
                    #if DEBUG 
                        if (ownerGrid.inGridViewCreate) { 
                            throw new Exception("PERF REGRESSION - Creating item in grid view create");
                        } 
                    #endif

                    btnDropDown = new DropDownButton();
                    btnDropDown.UseComboBoxTheme = true; 
                    Bitmap bitmap = CreateDownArrow();
                    btnDropDown.Image = bitmap; 
                    btnDropDown.BackColor = SystemColors.Control; 
                    btnDropDown.ForeColor = SystemColors.ControlText;
                    btnDropDown.Click += new EventHandler(this.OnBtnClick); 
                   // btnDropDown.MouseUp += new MouseEventHandler(this.OnBtnMouseUp);
                   // btnDropDown.MouseDown += new MouseEventHandler(this.OnBtnMouseDown);
                    btnDropDown.LostFocus += new EventHandler(this.OnChildLostFocus);
                    btnDropDown.TabIndex = 2; 
                    CommonEditorSetup(btnDropDown);
                    btnDropDown.Size = new Size(SystemInformation.VerticalScrollBarArrowHeight, RowHeight); 
                } 
                return btnDropDown;
            } 
        }

        private Button DialogButton {
            get { 
                if (btnDialog == null) {
 
                    #if DEBUG 
                    if (ownerGrid.inGridViewCreate) {
                        throw new Exception("PERF REGRESSION - Creating item in grid view create"); 
                    }
                    #endif
                    btnDialog = new DropDownButton();
                    btnDialog.BackColor = SystemColors.Control; 
                    btnDialog.ForeColor = SystemColors.ControlText;
                    btnDialog.TabIndex = 3; 
                    btnDialog.Image = new Bitmap(typeof(PropertyGrid), "dotdotdot.png"); 
                    btnDialog.Click += new EventHandler(this.OnBtnClick);
                    //btnDialog.MouseUp += new MouseEventHandler(this.OnBtnMouseUp); 
                    //btnDialog.MouseDown += new MouseEventHandler(this.OnBtnMouseDown);
                    btnDialog.KeyDown += new KeyEventHandler(this.OnBtnKeyDown);
                    btnDialog.LostFocus += new EventHandler(this.OnChildLostFocus);
                    btnDialog.Size = new Size(SystemInformation.VerticalScrollBarArrowHeight, RowHeight); 
                    CommonEditorSetup(btnDialog);
                } 
                return btnDialog; 
            }
        } 

        private GridViewEdit Edit {
            get{
                if (edit == null) { 

                    #if DEBUG 
                    if (ownerGrid.inGridViewCreate) { 
                        throw new Exception("PERF REGRESSION - Creating item in grid view create");
                    } 
                    #endif

                    edit = new GridViewEdit(this);
                    edit.BorderStyle = BorderStyle.None; 
                    edit.AutoSize = false;
                    edit.TabStop = false; 
                    edit.AcceptsReturn = true; 
                    edit.BackColor = BackColor;
                    edit.ForeColor = ForeColor; 
                    edit.KeyDown += new KeyEventHandler(this.OnEditKeyDown);
                    edit.KeyPress += new KeyPressEventHandler(this.OnEditKeyPress);
                    edit.GotFocus += new EventHandler(this.OnEditGotFocus);
                    edit.LostFocus += new EventHandler(this.OnEditLostFocus); 
                    edit.MouseDown += new MouseEventHandler(this.OnEditMouseDown);
                    edit.TextChanged += new EventHandler(this.OnEditChange); 
                    //edit.ImeModeChanged += new EventHandler(this.OnEditImeModeChanged); 
                    edit.TabIndex = 1;
                    CommonEditorSetup(edit); 
                }
                return edit;
            }
        } 

        private GridViewListBox DropDownListBox { 
            get { 
                if (listBox == null) {
                    #if DEBUG 
                    if (ownerGrid.inGridViewCreate) {
                        throw new Exception("PERF REGRESSION - Creating item in grid view create");
                    }
                    #endif 

                    listBox = new GridViewListBox(this); 
                    listBox.DrawMode = DrawMode.OwnerDrawFixed; 
                    //listBox.Click += new EventHandler(this.OnListClick);
                    listBox.MouseUp += new MouseEventHandler(this.OnListMouseUp); 
                    listBox.DrawItem += new DrawItemEventHandler(this.OnListDrawItem);
                    listBox.SelectedIndexChanged += new EventHandler(this.OnListChange);
                    listBox.KeyDown += new KeyEventHandler(this.OnListKeyDown);
                    listBox.LostFocus += new EventHandler(this.OnChildLostFocus); 
                    listBox.Visible = true;
                    listBox.ItemHeight = RowHeight; 
                } 
                return listBox;
            } 
        }

        internal bool DrawValuesRightToLeft {
            get { 
                if (edit != null && edit.IsHandleCreated) {
                    int exStyle = unchecked((int)((long)UnsafeNativeMethods.GetWindowLong(new HandleRef(edit, edit.Handle), NativeMethods.GWL_EXSTYLE))); 
                    return ((exStyle & NativeMethods.WS_EX_RTLREADING) != 0); 
                }
                else { 
                    return false;
                }
            }
        } 

 
        public bool FocusInside { 
            get {
                return(this.ContainsFocus || (dropDownHolder != null && dropDownHolder.ContainsFocus)); 
            }
        }

        internal Color GrayTextColor{ 
            get {
                if (this.ForeColor.ToArgb() == SystemColors.WindowText.ToArgb()) { 
                    return SystemColors.GrayText; 
                }
 
                // compute the new color by halving the value of the old one.
                //
                int colorRGB = this.ForeColor.ToArgb();
 
                int alphaValue = (colorRGB >> 24) & 0xff;
                if (alphaValue != 0) { 
                    alphaValue /= 2; 
                    colorRGB &= 0xFFFFFF;
                    colorRGB |= (int)((alphaValue << 24) & 0xFF000000); 
                }
                else {
                    colorRGB /= 2;
                } 
                return Color.FromArgb(colorRGB);
            } 
        } 

        private GridErrorDlg ErrorDialog { 
            get {
                if (this.errorDlg == null) {
                    errorDlg = new GridErrorDlg(this.ownerGrid);
                } 
                return errorDlg;
            } 
        } 

        private bool HasEntries { 
            get{
                return topLevelGridEntries != null && topLevelGridEntries.Count > 0;
            }
        } 

        protected int InternalLabelWidth { 
            get { 
                if (GetFlag(FlagNeedUpdateUIBasedOnFont)) {
                    UpdateUIBasedOnFont(true); 
                }
                if (labelWidth == -1) {
                    SetConstants();
                } 
                return labelWidth;
            } 
        } 

        internal int LabelPaintMargin { 

            set {
                requiredLabelPaintMargin = (short)Math.Max(Math.Max(value, requiredLabelPaintMargin), GDIPLUS_SPACE);
            } 
        }
 
        protected bool NeedsCommit{ 
            get {
                string text; 

                if (edit==null || !Edit.Visible) {
                    return false;
                } 

                text = Edit.Text; 
 
                if (((text == null || text.Length == 0) && (originalTextValue == null || originalTextValue.Length == 0)) ||
                    (text != null && originalTextValue != null && text.Equals(originalTextValue))) { 
                    return false;
                }
                return true;
            } 
        }
 
        public PropertyGrid OwnerGrid{ 
            get{
                return this.ownerGrid; 
            }
        }

        protected int RowHeight { 
            get {
                if (cachedRowHeight == -1) { 
                    cachedRowHeight = (int)Font.Height + 2; 
                }
                return cachedRowHeight; 
            }
        }

        ///  
        /// 
        /// 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. 
        /// 
        public Point ContextMenuDefaultLocation {
            get {
                // get the rect for the currently selected prop name, find the middle 
                Rectangle rect = GetRectangle( selectedRow, ROWLABEL );
                Point pt = PointToScreen( new Point( rect.X, rect.Y ) ); 
                return new Point(pt.X + (rect.Width / 2), pt.Y + (rect.Height / 2)); 
            }
        } 

        private ScrollBar ScrollBar {
            get {
                if (scrollBar == null) { 
                    #if DEBUG
                    if (ownerGrid.inGridViewCreate) { 
                        throw new Exception("PERF REGRESSION - Creating item in grid view create"); 
                    }
                    #endif 
                    scrollBar = new VScrollBar();
                    scrollBar.Scroll += new ScrollEventHandler(this.OnScroll);
                    Controls.Add(scrollBar);
                } 
                return scrollBar;
            } 
        } 

        internal GridEntry SelectedGridEntry { 
            get {
                return selectedGridEntry;
            }
            set { 
                if (allGridEntries != null) {
                    foreach (GridEntry e in allGridEntries) { 
                        if (e == value) { 
                            SelectGridEntry(value, true);
                            return; 
                        }
                    }
                }
 
                GridEntry gr = FindEquivalentGridEntry(new GridEntryCollection(null, new GridEntry[]{value}));
 
                if (gr != null) { 
                    SelectGridEntry(gr, true);
                    return; 
                }

                throw new ArgumentException(SR.GetString(SR.PropertyGridInvalidGridEntry));
            } 
        }
 
        /* 
        public PropertyDescriptor SelectedPropertyDescriptor {
            get { 
                if (selectedGridEntry != null && (selectedGridEntry is PropertyDescriptorGridEntry)) {
                    return ((PropertyDescriptorGridEntry) selectedGridEntry).PropertyDescriptor;
                }
                else { 
                    return null;
                } 
            } 
        }
        */ 

        /*
        /// 
        ///  
        /// Returns the currently selected property name.
        /// If no property or a category name is selected, "" is returned. 
        /// If the category is a sub property, it is concatenated onto its 
        /// parent property name with a ".".
        ///  
        public string SelectedPropertyName {
            get {
                if (selectedGridEntry == null) {
                    return ""; 
                }
                GridEntry gridEntry = selectedGridEntry; 
                string name = ""; 
                while (gridEntry != null && gridEntry.PropertyDepth >= 0) {
                    if (name.Length > 0) { 
                        name = gridEntry.PropertyName + "." + name;
                    }
                    else {
                        name = gridEntry.PropertyName; 
                    }
                    gridEntry = gridEntry.ParentGridEntry; 
                } 
                return name;
            } 
            set{
                if (value==null){
                    return;
                } 
                if (value.Equals(selectedGridEntry.PropertyLabel)){
                    return; 
                } 

                string curName; 
                string remain = value;

                int dot = remain.IndexOf('.');
                GridEntry[] ipes = GetAllGridEntries(); 
                int pos = 0;
 
                while (dot != -1){ 
                    curName = remain.Substring(0, dot);
                    Debug.WriteLine("Looking for: " + curName); 
                    for (int i = pos; i < ipes.Length ; i++){
                        Debug.WriteLine("Checking : " + ipes[i].PropertyLabel);
                        if (ipes[i].PropertyLabel.Equals(curName)){
                            if (ipes[i].Expandable){ 
                                pos = i;
                                remain = remain.Substring(dot + 1); 
                                dot = remain.IndexOf('.'); 
                                if (dot != -1){
                                    Debug.WriteLine("Expanding: " + ipes[i].PropertyLabel); 
                                    ipes[i].SetPropertyExpand(true);
                                    ipes = GetAllGridEntries();
                                    break;
                                } 
                                else{
                                    SelectGridEntry(ipes[i], true); 
                                    return; 
                                }
                            } 
                        }
                    }
                    // uh oh
                    dot = -1; 
                }
                // oops, didn't find it 
                SelectRow(0); 
                return;
 
            }
        }
        */
 
        /// 
        ///  
        /// Returns or sets the IServiceProvider the PropertyGridView will use to obtain 
        /// services.  This may be null.
        ///  
        public IServiceProvider ServiceProvider {
            get {
               return serviceProvider;
            } 
            set {
               if (value != serviceProvider) { 
                    this.serviceProvider = value; 

                    topHelpService = null; 

                    if (helpService != null && helpService is IDisposable)
                        ((IDisposable)helpService).Dispose();
 
                    helpService = null;
               } 
            } 
        }
 
        private int TipColumn {
            get{
                return(tipInfo & unchecked((int)0xFFFF0000)) >> 16;
            } 
            set{
 
                // clear the column 
                tipInfo &= 0xFFFF;
 
                // set the row
                tipInfo |= ((value & 0xFFFF) << 16);
            }
        } 

        private int TipRow { 
            get{ 
                return tipInfo & 0xFFFF;
            } 
            set{

                // clear the row
                tipInfo &= unchecked((int)0xFFFF0000); 

                // set the row 
                tipInfo |= (value & 0xFFFF); 
            }
        } 

        private GridToolTip ToolTip {
            get {
                if (toolTip == null) { 
                    #if DEBUG
                    if (ownerGrid.inGridViewCreate) { 
                        throw new Exception("PERF REGRESSION - Creating item in grid view create"); 
                    }
                    #endif 
                    toolTip = new GridToolTip(new Control[]{this, Edit});
                    toolTip.ToolTip = "";
                    toolTip.Font = this.Font;
                } 
                return toolTip;
            } 
        } 

        internal GridEntryCollection AccessibilityGetGridEntries() { 
            return GetAllGridEntries();
        }

        internal Rectangle AccessibilityGetGridEntryBounds(GridEntry gridEntry) { 
            int row = GetRowFromGridEntry(gridEntry);
            if (row == -1) { 
                return new Rectangle(0, 0, 0, 0); 
            }
            Rectangle rect = GetRectangle(row, ROWVALUE | ROWLABEL); 

            // Translate rect to screen coordinates
            //
            NativeMethods.POINT pt = new NativeMethods.POINT(rect.X, rect.Y); 
            UnsafeNativeMethods.ClientToScreen(new HandleRef(this, Handle), pt);
 
            return new Rectangle(pt.x, pt.y, rect.Width, rect.Height); 
        }
 
        internal int AccessibilityGetGridEntryChildID(GridEntry gridEntry) {

            GridEntryCollection ipes = GetAllGridEntries();
 
            if (ipes == null) {
                return -1; 
            } 

            // Find the grid entry and return its ID 
            //
            for(int index = 0; index < ipes.Count; ++index) {
                if (ipes[index].Equals(gridEntry)) {
                    return index; 
                }
            } 
 
            return -1;
        } 

        internal void AccessibilitySelect(GridEntry entry) {
            SelectGridEntry(entry, true);
            FocusInternal(); 
        }
 
        private void AddGridEntryEvents(GridEntryCollection ipeArray, int startIndex, int count) { 
            if (ipeArray == null) {
                return; 
            }

            if (count == -1) {
                count = ipeArray.Count - startIndex; 
            }
 
            for (int i= startIndex; i < (startIndex + count); i++) { 
                if (ipeArray[i] != null) {
                    GridEntry ge = ipeArray.GetEntry(i); 
                    ge.AddOnValueClick(ehValueClick);
                    ge.AddOnLabelClick(ehLabelClick);
                    ge.AddOnOutlineClick(ehOutlineClick);
                    ge.AddOnOutlineDoubleClick(ehOutlineClick); 
                    ge.AddOnValueDoubleClick(ehValueDblClick);
                    ge.AddOnLabelDoubleClick(ehLabelDblClick); 
                    ge.AddOnRecreateChildren(ehRecreateChildren); 
                }
            } 
        }

        protected virtual void AdjustOrigin(System.Drawing.Graphics g, Point newOrigin, ref Rectangle r) {
 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Adjusting paint origin to (" + newOrigin.X.ToString(CultureInfo.InvariantCulture) + "," + newOrigin.Y.ToString(CultureInfo.InvariantCulture) + ")");
 
            g.ResetTransform(); 
            g.TranslateTransform(newOrigin.X, newOrigin.Y);
            r.Offset(-newOrigin.X, -newOrigin.Y); 
        }

        private void CancelSplitterMove() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CancelSplitterMove"); 
            if (GetFlag(FlagIsSplitterMove)) {
                SetFlag(FlagIsSplitterMove, false); 
                CaptureInternal = false; 

                if (selectedRow != -1) { 
                    SelectRow(selectedRow);
                }
            }
        } 

        internal GridPositionData CaptureGridPositionData() { 
            return new GridPositionData(this); 
        }
 
        private void ClearGridEntryEvents(GridEntryCollection ipeArray, int startIndex, int count) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:ClearGridEntryEvents");
            if (ipeArray == null) {
                return; 
            }
 
            if (count == -1) { 
                count = ipeArray.Count - startIndex;
            } 

            for (int i = startIndex ; i < (startIndex + count); i++) {
                if (ipeArray[i] != null) {
                    GridEntry ge = ipeArray.GetEntry(i); 
                    ge.RemoveOnValueClick(ehValueClick);
                    ge.RemoveOnLabelClick(ehLabelClick); 
                    ge.RemoveOnOutlineClick(ehOutlineClick); 
                    ge.RemoveOnOutlineDoubleClick(ehOutlineClick);
                    ge.RemoveOnValueDoubleClick(ehValueDblClick); 
                    ge.RemoveOnLabelDoubleClick(ehLabelDblClick);
                    ge.RemoveOnRecreateChildren(ehRecreateChildren);
                }
            } 
        }
 
        public void ClearProps() { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:ClearProps");
 

            if (!HasEntries) {
                return;
            } 

            CommonEditorHide(); 
            topLevelGridEntries = null; 
            ClearGridEntryEvents(allGridEntries, 0, -1);
            allGridEntries = null; 
            selectedRow = -1;
            //selectedGridEntry = null; // we don't wanna clear this because then we can't save where we were on a Refresh()
            tipInfo = -1;
        } 

        ///  
        ///  
        ///      Closes a previously opened drop down.  This should be called by the
        ///      drop down when the user does something that should close it. 
        /// 
        public void /* IWindowsFormsEditorService. */ CloseDropDown() {
            CloseDropDownInternal(true);
        } 

        private void CloseDropDownInternal(bool resetFocus) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CloseDropDown"); 

            // the activation code in the DropDownHolder can cause this to recurse... 

            if (GetFlag(FlagDropDownClosing)) {
                return;
            } 
            try {
                SetFlag(FlagDropDownClosing, true); 
                if (dropDownHolder != null && dropDownHolder.Visible) { 

                    if (dropDownHolder.Component == DropDownListBox && GetFlag(FlagDropDownCommit)) { 
                        OnListClick(null,  null);
                    }

                    Edit.Filter = false; 

                    // disable the ddh so it wont' steal the focus back 
                    // 
                    dropDownHolder.SetComponent(null, false);
                    dropDownHolder.Visible = false; 

                    // when we disable the dropdown holder, focus will be lost,
                    // so put it onto one of our children first.
                    if (resetFocus) { 
                        if (DialogButton.Visible) {
                            DialogButton.FocusInternal(); 
                        } 
                        else if (DropDownButton.Visible) {
                            DropDownButton.FocusInternal(); 
                        }
                        else if (Edit.Visible) {
                            Edit.FocusInternal();
                        } 
                        else {
                            FocusInternal(); 
                        } 

                        if (selectedRow != -1) { 
                            SelectRow(selectedRow);
                        }
                    }
                } 
            }
            finally { 
                SetFlag(FlagDropDownClosing, false); 
            }
        } 

        private void CommonEditorHide() {
                CommonEditorHide(false);
        } 

        private void CommonEditorHide(bool always) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CommonEditorHide"); 

            if (!always && !HasEntries) { 
                return;
            }

            CloseDropDown(); 

            bool gotfocus = false; 
 
            if (Edit.Focused || DialogButton.Focused || DropDownButton.Focused) {
 
                if (IsHandleCreated && Visible && Enabled) {

                    gotfocus = IntPtr.Zero != UnsafeNativeMethods.SetFocus(new HandleRef(this, Handle));
                } 
            }
 
            try { 
               // We do this becuase the Focus call above doesn't always stick, so
               // we make the Edit think that it doesn't have focus.  this prevents 
               // ActiveControl code on the containercontrol from moving focus elsewhere
               // when the dropdown closes.
               Edit.DontFocus = true;
               if (Edit.Focused && !gotfocus) { 
                 gotfocus = this.FocusInternal();
               } 
               Edit.Visible = false; 

               Edit.SelectionStart = 0; 
               Edit.SelectionLength = 0;

               if (DialogButton.Focused && !gotfocus) {
                  gotfocus = this.FocusInternal(); 
               }
               DialogButton.Visible = false; 
 
               if (DropDownButton.Focused && !gotfocus) {
                   gotfocus = this.FocusInternal(); 
               }
               DropDownButton.Visible = false;
               currentEditor = null;
            } 
            finally {
               Edit.DontFocus = false; 
            } 
        }
 
        protected virtual void CommonEditorSetup(Control ctl) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CommonEditorSetup");
            ctl.Visible = false;
            Controls.Add(ctl); 
        }
 
        protected virtual void CommonEditorUse(Control ctl, Rectangle rectTarget) { 

            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CommonEditorUse"); 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Showing common editors");

            Debug.Assert(ctl != null, "Null control passed to CommonEditorUse");
 
            Rectangle rectCur = ctl.Bounds;
 
            // the client rect minus the border line 
            Rectangle clientRect = this.ClientRectangle;
 
            clientRect.Inflate(-1,-1);

            try {
                rectTarget = Rectangle.Intersect(clientRect, rectTarget); 
                 //if (ctl is Button)
                 //   Debug.WriteStackTrace(); 
 

                if (!rectTarget.IsEmpty) { 
                    if (!rectTarget.Equals(rectCur)) {
                        ctl.SetBounds(rectTarget.X,rectTarget.Y,
                                      rectTarget.Width,rectTarget.Height);
                    } 
                    ctl.Visible = true;
                } 
            } 
            catch {
                rectTarget = Rectangle.Empty; 
            }

            if (rectTarget.IsEmpty) {
 
                ctl.Visible = false;
            } 
 
            currentEditor = ctl;
 
        }

        private /*protected virtual*/ int CountPropsFromOutline(GridEntryCollection rgipes) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CountPropsFromOutLine"); 
            if (rgipes == null) return 0;
            int cProps = rgipes.Count; 
            for (int i = 0; i < rgipes.Count; i++) { 
                if (((GridEntry)rgipes[i]).InternalExpanded)
                    cProps += CountPropsFromOutline(((GridEntry)rgipes[i]).Children); 
            }
            return cProps;
        }
 
        /// 
        ///  
        ///     Constructs the new instance of the accessibility object for this control. Subclasses 
        ///     should not call base.CreateAccessibilityObject.
        ///  
        protected override AccessibleObject CreateAccessibilityInstance() {
            return new PropertyGridViewAccessibleObject(this);
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        private Bitmap CreateDownArrow() { 
            Bitmap bitmap = null;
 
            try
            {
                Icon icon = new Icon(typeof(PropertyGrid), "Arrow.ico");
                bitmap = icon.ToBitmap(); 
                icon.Dispose();
            } 
            catch (Exception e) 
            {
                Debug.Fail(e.ToString()); 
                bitmap = new Bitmap(16, 16);
            }
            return bitmap;
        } 

 
        protected virtual void CreateUI() { 
            UpdateUIBasedOnFont(false);
        } 

        protected override void Dispose(bool disposing) {
            if (disposing) {
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Dispose"); 
                if (scrollBar != null) scrollBar.Dispose();
                if (listBox != null) listBox.Dispose(); 
                if (dropDownHolder != null) dropDownHolder.Dispose(); 
                scrollBar = null;
                listBox = null; 
                dropDownHolder = null;

                ownerGrid = null;
                topLevelGridEntries = null; 
                allGridEntries = null;
                serviceProvider = null; 
 
                topHelpService = null;
 
                if (helpService != null && helpService is IDisposable)
                    ((IDisposable)helpService).Dispose();

                helpService = null; 

                if (edit != null) { 
                    edit.Dispose(); 
                    edit = null;
                } 

                if (fontBold != null) {
                    fontBold.Dispose();
                    fontBold = null; 

                } 
 
                if (btnDropDown != null) {
                    btnDropDown.Dispose(); 
                    btnDropDown = null;
                }

                if (btnDialog != null) { 
                    btnDialog.Dispose();
                    btnDialog = null; 
                } 

                if (toolTip != null) { 
                    toolTip.Dispose();
                    toolTip = null;
                }
            } 

            base.Dispose(disposing); 
        } 

        public void DoCopyCommand() { 
            if (this.CanCopy) {
               if (Edit.Focused) {
                    Edit.Copy();
               } 
               else {
                    Clipboard.SetDataObject(selectedGridEntry.GetPropertyTextValue()); 
               } 
            }
        } 

        public void DoCutCommand() {
            if (this.CanCut) {
               DoCopyCommand(); 
               if (Edit.Visible) {
                    Edit.Cut(); 
               } 
            }
        } 


        public void DoPasteCommand() {
            if (this.CanPaste && Edit.Visible) { 
               if (Edit.Focused) {
                    Edit.Paste(); 
               } 
               else {
                   IDataObject dataObj = Clipboard.GetDataObject(); 
                   if (dataObj != null) {
                      string data = (string)dataObj.GetData(typeof(string));
                      if (data != null) {
                         Edit.FocusInternal(); 
                         Edit.Text = data;
                         SetCommitError(ERROR_NONE, true); 
                      } 
                   }
               } 
            }
        }

        public void DoUndoCommand() { 
            if (this.CanUndo && Edit.Visible) {
               Edit.SendMessage(NativeMethods.WM_UNDO, 0, 0); 
            } 
        }
 
        internal void DumpPropsToConsole(GridEntry entry, string prefix) {

            Type propType = entry.PropertyType;
 
            if (entry.PropertyValue != null) {
               propType = entry.PropertyValue.GetType(); 
            } 

            System.Console.WriteLine(prefix + entry.PropertyLabel + ", value type=" + (propType == null ? "(null)" : propType.FullName) + ", value=" + (entry.PropertyValue == null ? "(null)" : entry.PropertyValue.ToString()) + 
                                     ", flags=" + entry.Flags.ToString(CultureInfo.InvariantCulture) +
                                     ", TypeConverter=" + (entry.TypeConverter == null ? "(null)" : entry.TypeConverter.GetType().FullName) + ", UITypeEditor=" + ((entry.UITypeEditor == null ? "(null)" : entry.UITypeEditor.GetType().FullName)));
            GridEntryCollection children = entry.Children;
 
            if (children != null) {
               foreach(GridEntry g in children) { 
                  DumpPropsToConsole(g, prefix + "\t"); 
               }
            } 
        }

        private int GetIPELabelIndent(GridEntry gridEntry) {
            //return OUTLINE_INDENT*(gridEntry.PropertyDepth + 1); 
            return gridEntry.PropertyLabelIndent + 1;
        } 
 
        private int GetIPELabelLength(System.Drawing.Graphics g, GridEntry gridEntry) {
            SizeF sizeF = PropertyGrid.MeasureTextHelper.MeasureText(this.ownerGrid, g, gridEntry.PropertyLabel, Font); 
            Size size = Size.Ceiling(sizeF);
            return ptOurLocation.X + GetIPELabelIndent(gridEntry) + size.Width;
        }
 
        private bool IsIPELabelLong(System.Drawing.Graphics g,GridEntry gridEntry) {
            if (gridEntry == null) return false; 
            int length = GetIPELabelLength(g,gridEntry); 
            return(length > ptOurLocation.X + InternalLabelWidth);
        } 

        protected virtual void DrawLabel(System.Drawing.Graphics g, int row, Rectangle rect, bool selected, bool fLongLabelRequest, ref Rectangle clipRect) {

            GridEntry gridEntry = GetGridEntryFromRow(row); 

            if (gridEntry == null || rect.IsEmpty) 
                return; 

            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Drawing label for property " + gridEntry.PropertyLabel); 

            Point newOrigin = new Point(rect.X, rect.Y);
            Rectangle cr = Rectangle.Intersect(rect, clipRect);
 
            if (cr.IsEmpty) {
                return; 
            } 

            AdjustOrigin(g, newOrigin, ref rect); 
            cr.Offset(-newOrigin.X, -newOrigin.Y);

            try {
                try 
                {
                    bool fLongLabel = false; 
                    int labelEnd = 0; 
                    int labelIndent = GetIPELabelIndent(gridEntry);
 
                    if (fLongLabelRequest)
                    {
                        labelEnd = GetIPELabelLength(g, gridEntry);
                        fLongLabel = IsIPELabelLong(g, gridEntry); 
                    }
 
                    gridEntry.PaintLabel(g, rect, cr, selected, fLongLabel); 
                }
                catch (Exception ex) 
                {
                    Debug.Fail(ex.ToString());
                }
            } 
            finally {
                ResetOrigin(g); 
            } 
        }
 
        protected virtual void DrawValueEntry(System.Drawing.Graphics g, int row, ref Rectangle clipRect) {
            GridEntry gridEntry = GetGridEntryFromRow(row);
            if (gridEntry == null)
                return; 

            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Drawing value for property " + gridEntry.PropertyLabel); 
 
            Rectangle r = GetRectangle(row,ROWVALUE);
            Point newOrigin = new Point(r.X, r.Y); 
            Rectangle cr = Rectangle.Intersect(clipRect, r);

            if (cr.IsEmpty) {
                return; 
            }
 
            AdjustOrigin(g, newOrigin, ref r); 
            cr.Offset(-newOrigin.X, -newOrigin.Y);
 
            try {
                try {
                    DrawValueEntry(g,r, cr,gridEntry,null, true);
                } 
                catch {
                } 
            } 
            finally {
                ResetOrigin(g); 
            }
        }

        private /*protected virtual*/ void DrawValueEntry(System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, GridEntry gridEntry, object value, bool fetchValue) { 
            DrawValue(g, rect, clipRect, gridEntry, value, false, true, fetchValue, true);
        } 
        private void DrawValue(System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, GridEntry gridEntry, object value, bool drawSelected, bool checkShouldSerialize, bool fetchValue, bool paintInPlace) { 
            GridEntry.PaintValueFlags paintFlags = GridEntry.PaintValueFlags.None;
 
            if(drawSelected) {
                paintFlags |= GridEntry.PaintValueFlags.DrawSelected;
            }
 
            if (checkShouldSerialize) {
               paintFlags |= GridEntry.PaintValueFlags.CheckShouldSerialize; 
            } 

            if (fetchValue) { 
                paintFlags |= GridEntry.PaintValueFlags.FetchValue;
            }

            if (paintInPlace) { 
                paintFlags |= GridEntry.PaintValueFlags.PaintInPlace;
            } 
 
            gridEntry.PaintValue(value, g, rect, clipRect, paintFlags);
        } 

        private void F4Selection(bool popupModalDialog) {
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null) return; 

            // if we are in an errorState, just put the focus back on the Edit 
            if (errorState != ERROR_NONE && Edit.Visible) { 
                Edit.FocusInternal();
                return; 
            }

            if (DropDownButton.Visible) {
                PopupDialog(selectedRow); 
            }
            else if (DialogButton.Visible) { 
                if (popupModalDialog) { 
                    PopupDialog(selectedRow);
                } 
                else {
                    DialogButton.FocusInternal();
                }
            } 
            else if (Edit.Visible) {
                Edit.FocusInternal(); 
                SelectEdit(false); 
            }
            return; 
        }

        //The following Suppress message calls are required so we can handle
        //errors when attempting to generate an event handler when the document 
        //is read-only.  This code is a duplicate of the error handling in
        //CommitValue(). 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
        public void DoubleClickRow(int row, bool toggleExpand, int type) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:DoubleClickRow");
            GridEntry gridEntry = GetGridEntryFromRow(row);
            if (gridEntry == null) return;
 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Property " + gridEntry.PropertyLabel + " double clicked");
 
            if (!toggleExpand || type == ROWVALUE) { 
                try {
                    bool action = gridEntry.DoubleClickPropertyValue(); 
                    if (action) {
                        SelectRow(row);
                        return;
                    } 
                }
                catch (Exception ex) { 
                    SetCommitError(ERROR_THROWN); 
                    ShowInvalidMessage(gridEntry.PropertyLabel, null, ex);
                    return; 
                }
            }

            SelectGridEntry(gridEntry, true); 

            if (type == ROWLABEL && toggleExpand && gridEntry.Expandable) { 
                SetExpand(gridEntry,!gridEntry.InternalExpanded); 
                return;
            } 

            if (gridEntry.IsValueEditable && gridEntry.Enumerable) {
                int index = GetCurrentValueIndex(gridEntry);
 
                if (index != -1) {
                    object[] values = gridEntry.GetPropertyValueList(); 
 
                    if (values == null || index >= (values.Length - 1)) {
                        index = 0; 
                    }
                    else {
                        index++;
                    } 

                    CommitValue(values[index]); 
                    SelectRow(selectedRow); 
                    Refresh();
                    return; 
                }
            }

            if (Edit.Visible) { 
                Edit.FocusInternal();
                SelectEdit(false); 
                return; 
            }
        } 

        public Font GetBaseFont() {
            return Font;
        } 

        public Font GetBoldFont() { 
            if (fontBold == null) { 
                fontBold = new Font(this.Font, FontStyle.Bold);
            } 
            return fontBold;
        }

        internal IntPtr GetBaseHfont() { 
            if (baseHfont == IntPtr.Zero) {
                baseHfont = GetBaseFont().ToHfont(); 
            } 
            return baseHfont;
        } 

        internal IntPtr GetBoldHfont() {
            if (boldHfont == IntPtr.Zero) {
                boldHfont = GetBoldFont().ToHfont(); 
            }
            return boldHfont; 
        } 

 
        private bool GetFlag(short flag) {
            return (this.flags & flag) != 0;
        }
 
        public virtual Color GetLineColor() {
            return ownerGrid.LineColor; 
        } 

        public virtual Brush GetLineBrush(Graphics g) { 
            if (ownerGrid.lineBrush == null) {
                Color clr = g.GetNearestColor(ownerGrid.LineColor);
                ownerGrid.lineBrush = new SolidBrush(clr);
            } 
            return ownerGrid.lineBrush;
        } 
 
        public virtual IntPtr GetHostHandle() {
            return Handle; 
        }

        public virtual int GetLabelWidth() {
            return InternalLabelWidth; 
        }
 
        internal bool IsExplorerTreeSupported { 
            get {
                if (UnsafeNativeMethods.IsVista && VisualStyleRenderer.IsSupported) { 
                    return true;
                }

                return false; 
            }
        } 
 
        public virtual int GetOutlineIconSize() {
            if (IsExplorerTreeSupported) { 
                return OUTLINE_SIZE_EXPLORER_TREE_STYLE;
            }
            else {
                return OUTLINE_SIZE; 
            }
        } 
 
        public virtual int GetGridEntryHeight() {
            return RowHeight; 
        }

        // for qa automation
        internal int GetPropertyLocation(string propName, bool getXY, bool rowValue) { 
            if (allGridEntries != null && allGridEntries.Count > 0) {
                for (int i = 0; i < allGridEntries.Count; i++) { 
                    if (0 == String.Compare(propName, allGridEntries.GetEntry(i).PropertyLabel, true, CultureInfo.InvariantCulture)) { 
                        if (getXY) {
                            int row = GetRowFromGridEntry(allGridEntries.GetEntry(i)); 

                            if (row < 0 || row >= this.visibleRows) {
                                return -1;
                            } 
                            else {
                                Rectangle r = GetRectangle(row, rowValue ? ROWVALUE : ROWLABEL); 
                                return(r.Y << 16 | (r.X & 0xFFFF)); 
                            }
                        } 
                        else {
                            return i;
                        }
                    } 
                }
            } 
            return -1; 
        }
 
        public new object GetService(Type classService) {
            if (classService == typeof(IWindowsFormsEditorService)) {
                return this;
            } 
            if (ServiceProvider != null) {
                return serviceProvider.GetService(classService); 
            } 
            return null;
        } 

        public virtual int GetSplitterWidth() {
            return 1;
        } 

        public virtual int GetTotalWidth() { 
            return GetLabelWidth() + GetSplitterWidth() + GetValueWidth(); 
        }
 
        public virtual int GetValuePaintIndent() {
            return PAINT_INDENT;
        }
 
        public virtual int GetValuePaintWidth() {
            return PAINT_WIDTH; 
        } 

        public virtual int GetValueStringIndent() { 
            return EDIT_INDENT;
        }

        public virtual int GetValueWidth() { 
            return(int)(InternalLabelWidth * (labelRatio - 1));
        } 
 
        /// 
        ///  
        ///      Displays the provided control in a drop down.  When possible, the
        ///      current dimensions of the control will be respected.  If this is not possible
        ///      for the current screen layout the control may be resized, so it should
        ///      be implemented using appropriate docking and anchoring so it will resize 
        ///      nicely.  If the user performs an action that would cause the drop down
        ///      to prematurely disappear the control will be hidden. 
        ///  
        public void /* cpr IWindowsFormsEditorService. */ DropDownControl(Control ctl) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:DropDownControl"); 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "DropDownControl(ctl = " + ctl.GetType().Name + ")");
            if (dropDownHolder == null) {
                dropDownHolder = new DropDownHolder(this);
            } 

            dropDownHolder.Visible = false; 
            dropDownHolder.SetComponent(ctl, GetFlag(FlagResizableDropDown)); 
            Rectangle rect = GetRectangle(selectedRow,ROWVALUE);
            Size size = dropDownHolder.Size; 
            Point loc = PointToScreen(new Point(0, 0));
            Rectangle rectScreen = Screen.FromControl(Edit).WorkingArea;
            size.Width = Math.Max(rect.Width+1,size.Width);
 
            // Not needed... CYMAXDDLHEIGHT used to be 200, but why limit it???
            //size.Height = Math.Min(size.Height,CYMAXDDLHEIGHT); 
 
            loc.X = Math.Min(rectScreen.X + rectScreen.Width - size.Width,
                             Math.Max(rectScreen.X,loc.X + rect.X + rect.Width - size.Width)); 
            loc.Y += rect.Y;
            if (rectScreen.Y + rectScreen.Height < (size.Height + loc.Y + Edit.Height)) {
                loc.Y -= size.Height;
                dropDownHolder.ResizeUp = true; 
            }
            else { 
                loc.Y += rect.Height + 1; 
                dropDownHolder.ResizeUp = false;
            } 

            UnsafeNativeMethods.SetWindowLong(new HandleRef(dropDownHolder, dropDownHolder.Handle), NativeMethods.GWL_HWNDPARENT, new HandleRef(this, Handle));
            dropDownHolder.SetBounds(loc.X,loc.Y,size.Width,size.Height);
            SafeNativeMethods.ShowWindow(new HandleRef(dropDownHolder, dropDownHolder.Handle), NativeMethods.SW_SHOWNA); 
            Edit.Filter = true;
            dropDownHolder.Visible = true; 
 
            dropDownHolder.FocusComponent();
            SelectEdit(false); 

            try {
                DropDownButton.IgnoreMouse = true;
                dropDownHolder.DoModalLoop(); 
            }
            finally { 
                DropDownButton.IgnoreMouse = false; 
            }
 
            if (selectedRow != -1) {
                FocusInternal();
                SelectRow(selectedRow);
            } 
        }
 
        public virtual void DropDownDone() { 
            CloseDropDown();
        } 

        public virtual void DropDownUpdate() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:DropDownUpdate");
            if (dropDownHolder != null && dropDownHolder.GetUsed()) { 
                int row = selectedRow;
                GridEntry gridEntry = GetGridEntryFromRow(row); 
                Edit.Text = gridEntry.GetPropertyTextValue(); 
            }
        } 

        public bool EnsurePendingChangesCommitted() {
            this.CloseDropDown();
            return this.Commit(); 
        }
 
        private bool FilterEditWndProc(ref Message m) { 
            // if it's the TAB key, we keep it since we'll give them focus with it.
            if (dropDownHolder != null && dropDownHolder.Visible && m.Msg == NativeMethods.WM_KEYDOWN && (int)m.WParam != (int)Keys.Tab) { 
                Control ctl = dropDownHolder.Component;
                if (ctl != null) {
                    m.Result = ctl.SendMessage(m.Msg, m.WParam, m.LParam);
                    return true; 
                }
            } 
            return false; 
        }
 
        private bool FilterReadOnlyEditKeyPress(char keyChar) {
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry.Enumerable && gridEntry.IsValueEditable) {
                int index = GetCurrentValueIndex(gridEntry); 

                object[] values = gridEntry.GetPropertyValueList(); 
                string letter = new string(new char[] {keyChar}); 
                for (int i = 0; i < values.Length; i++) {
                    object valueCur = values[(i + index + 1) % values.Length]; 
                    string text = gridEntry.GetPropertyTextValue(valueCur);
                    if (text != null && text.Length > 0 && String.Compare(text.Substring(0,1), letter, true, CultureInfo.InvariantCulture) == 0) {
                        CommitValue(valueCur);
                        if (Edit.Focused) { 
                            SelectEdit(false);
                        } 
                        return true; 
                    }
                } 

            }
            return false;
        } 

        public virtual bool WillFilterKeyPress(char charPressed) { 
            if (!Edit.Visible) { 
                return false;
            } 

            Keys modifiers = ModifierKeys;
            if ((int)(modifiers & ~Keys.Shift) != 0) {
                return false; 
            }
 
            // try to activate the Edit. 
            // we don't activate for +,-, or * on expandable items because they have special meaning
            // for the tree. 
            //

            if (selectedGridEntry != null) {
                switch (charPressed) { 
                    case '+':
                    case '-': 
                    case '*': 
                        return !selectedGridEntry.Expandable;
                    case unchecked( (char)(int)(long)Keys.Tab): 
                        return false;
                }
            }
 
            return true;
        } 
 
        public void FilterKeyPress(char keyChar) {
 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null)
                return;
 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:FilterKeyPress()");
 
            Edit.FilterKeyPress(keyChar); 
        }
 
        private /*protected virtual*/ GridEntry FindEquivalentGridEntry(GridEntryCollection ipeHier) {
            if (ipeHier == null || ipeHier.Count == 0)
                return null;
            GridEntryCollection rgipes = GetAllGridEntries(); 

            if (rgipes == null || rgipes.Count == 0) { 
                return null; 
            }
 
            GridEntry targetEntry = null;
            int row = 0;
            int count = rgipes.Count;
 
            for (int i = 0; i < ipeHier.Count; i++) {
 
                if (ipeHier[i] == null) { 
                    continue;
                } 

                // if we've got one above, and it's expandable,
                // expand it
                if (targetEntry != null) { 

                    // how many do we have? 
                    int items = rgipes.Count; 

                    // expand and get the new count 
                    if (!targetEntry.InternalExpanded) {
                      SetExpand(targetEntry, true);
                      rgipes = GetAllGridEntries();
                    } 
                    count = targetEntry.VisibleChildCount;
                } 
 
                int start = row;
                targetEntry = null; 

                // now, we will only go as many as were expanded...
                for (; row < rgipes.Count && ((row - start) <= count); row++) {
                    if (ipeHier.GetEntry(i).NonParentEquals(rgipes[row])) { 
                        targetEntry = rgipes.GetEntry(row);
                        row++; 
                        break; 
                    }
                } 

                // didn't find it...
                if (targetEntry == null) {
                    break; 
                }
            } 
 
            return targetEntry;
        } 

        protected virtual Point FindPosition(int x, int y) {
            if (RowHeight == -1)
                return InvalidPosition; 
            Size size = this.GetOurSize();
 
            if (x < 0 || x > size.Width + ptOurLocation.X) 
                return InvalidPosition;
            Point pt = new Point(ROWLABEL,0); 
            if (x > InternalLabelWidth + ptOurLocation.X)
                pt.X = ROWVALUE;
            pt.Y = (y-ptOurLocation.Y)/(1+RowHeight);
            return pt; 
        }
 
        public virtual void Flush() { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView::Flush()");
            if (Commit() && Edit.Focused) { 
                this.FocusInternal();
            }
        }
 
        private GridEntryCollection GetAllGridEntries() {
            return GetAllGridEntries(false); 
        } 

        private GridEntryCollection GetAllGridEntries(bool fUpdateCache) { 
            if (visibleRows == -1 || totalProps == -1 || !HasEntries) {
                return null;
            }
 
            if (allGridEntries != null && !fUpdateCache) {
                return allGridEntries; 
            } 

            GridEntry[] rgipes = new GridEntry[totalProps]; 
            try
            {
                GetGridEntriesFromOutline(topLevelGridEntries, 0, 0, rgipes);
            } 
            catch (Exception ex)
            { 
                Debug.Fail(ex.ToString()); 
            }
            allGridEntries = new GridEntryCollection(null, rgipes); 
            AddGridEntryEvents(allGridEntries, 0, -1);
            return allGridEntries;
        }
 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private int GetCurrentValueIndex(GridEntry gridEntry) { 
 
            if (!gridEntry.Enumerable) {
                return -1; 
            }

            try {
                object[] values = gridEntry.GetPropertyValueList(); 
                object value = gridEntry.PropertyValue;
                string textValue = gridEntry.TypeConverter.ConvertToString(gridEntry, value); 
 
                if (values != null && values.Length > 0) {
                    string itemTextValue; 
                    int stringMatch = -1;
                    int equalsMatch = -1;
                    for (int i = 0; i < values.Length; i++) {
 
                        object curValue = values[i];
 
                        // check real values against string values. 
                        itemTextValue = gridEntry.TypeConverter.ConvertToString(curValue);
                        if (value == curValue || 0 == String.Compare(textValue, itemTextValue, true, CultureInfo.InvariantCulture)) { 
                            stringMatch = i;
                        }
                        // now try .equals if they are both non-null
                        if (value != null && curValue != null && curValue.Equals(value)) { 
                            equalsMatch = i;
                        } 
 
                        if (stringMatch == equalsMatch && stringMatch != -1) {
                            return stringMatch; 
                        }
                    }

                    if (stringMatch != -1) { 
                        return stringMatch;
                    } 
 
                    if (equalsMatch != -1) {
                        return equalsMatch; 
                    }
                }
            }
            catch (Exception e) { 
                Debug.Fail(e.ToString());
            } 
            return -1; 

        } 

        public virtual int GetDefaultOutlineIndent() {
            return OUTLINE_INDENT;
        } 

        private IHelpService GetHelpService() { 
            if (helpService == null && ServiceProvider != null) { 
                topHelpService = (IHelpService)ServiceProvider.GetService(typeof(IHelpService));
                if (topHelpService != null) { 
                     IHelpService localHelpService = topHelpService.CreateLocalContext(HelpContextType.ToolWindowSelection);
                     if (localHelpService != null) {
                        helpService = localHelpService;
                     } 
                }
            } 
            return helpService; 
        }
 
        public virtual int GetScrollOffset() {
            //Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:GetScrollOffset");
            if (scrollBar == null) {
                return 0; 
            }
            int pos = ScrollBar.Value; 
            return pos; 
        }
 
        /// 
        /// 
        /// returns an array of IPE specifying the current heirarchy of ipes from the given
        /// gridEntry through its parents to the root. 
        /// 
        private GridEntryCollection GetGridEntryHierarchy(GridEntry gridEntry) { 
            if (gridEntry == null) { 
                return null;
            } 

            int depth = gridEntry.PropertyDepth;
            if (depth > 0) {
                GridEntry[] entries = new GridEntry[depth + 1]; 

                while (gridEntry != null && depth >= 0) { 
                    entries[depth] = gridEntry; 
                    gridEntry = gridEntry.ParentGridEntry;
                    depth = gridEntry.PropertyDepth; 
                }
                return new GridEntryCollection(null, entries);
            }
            return new GridEntryCollection(null, new GridEntry[]{gridEntry}); 
        }
 
        private /*protected virtual*/ GridEntry GetGridEntryFromRow(int row) { 
            return GetGridEntryFromOffset(row + GetScrollOffset());
        } 

        private /*protected virtual*/ GridEntry GetGridEntryFromOffset(int offset) {
            GridEntryCollection rgipesAll = GetAllGridEntries();
            if (rgipesAll != null) { 
                if (offset >= 0 && offset < rgipesAll.Count)
                    return rgipesAll.GetEntry(offset); 
            } 
            return null;
        } 

        private /*protected virtual*/ int GetGridEntriesFromOutline(GridEntryCollection rgipe, int cCur,
                                                 int cTarget, GridEntry[] rgipeTarget) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:GetGridEntriesFromOutline"); 
            if (rgipe == null || rgipe.Count == 0)
                return cCur; 
 
            cCur--; // want to account for each entry as we find it.
 
            for (int cLocal = 0; cLocal < rgipe.Count; cLocal++) {
                cCur++;
                if (cCur >= cTarget + rgipeTarget.Length)
                    break; 

                GridEntry ipeCur = rgipe.GetEntry(cLocal); 
 
                //Debug.Assert(ipeCur != null, "Null IPE at position " + cLocal.ToString());
 

                if (cCur >= cTarget)
                    rgipeTarget[cCur - cTarget] = ipeCur;
 
                if (ipeCur.InternalExpanded) {
                    GridEntryCollection subGridEntry = ipeCur.Children; 
                    //Debug.Assert(subGridEntry != null && subGridEntry.Length > 0 && subGridEntry[0] != null, "Expanded property " + ipeCur.PropertyLabel + " has no children!"); 
                    if (subGridEntry != null && subGridEntry.Count > 0) {
                        cCur = GetGridEntriesFromOutline(subGridEntry, 
                                                  cCur+1,cTarget,rgipeTarget);
                    }
                }
            } 

            return cCur; 
        } 

        private Size GetOurSize() { 
                Size size = ClientSize;
                if (size.Width == 0) {
                    Size sizeWindow = Size;
                    if (sizeWindow.Width > 10) { 
                        Debug.Fail("We have a bad client width!");
                        size.Width = sizeWindow.Width; 
                        size.Height = sizeWindow.Height; 
                    }
                } 
                if (!GetScrollbarHidden()) {
                    Size sizeScroll = ScrollBar.Size;
                    size.Width -= sizeScroll.Width;
                } 
                size.Width -= 2;
                size.Height -= 2; 
                return size; 
        }
 
        public Rectangle GetRectangle(int row, int flRow) {
            Rectangle rect = new Rectangle(0,0,0,0);
            Size size = this.GetOurSize();
 
            rect.X = ptOurLocation.X;
 
            bool fLabel = ((flRow & ROWLABEL) != 0); 
            bool fValue = ((flRow & ROWVALUE) != 0);
 
            if (fLabel && fValue) {
                rect.X = 1;
                rect.Width = size.Width - 1;
            } 
            else if (fLabel) {
                rect.X = 1; 
                rect.Width = InternalLabelWidth - 1; 
            }
            else if (fValue) { 
                rect.X = ptOurLocation.X + InternalLabelWidth;
                rect.Width = size.Width - InternalLabelWidth;
            }
 
            rect.Y = (row)*(RowHeight+1)+1+ptOurLocation.Y;
            rect.Height = RowHeight; 
 
            return rect;
        } 

        private /*protected virtual*/ int GetRowFromGridEntry(GridEntry gridEntry) {
            GridEntryCollection rgipesAll = GetAllGridEntries();
            if (gridEntry == null || rgipesAll == null) 
                return -1;
 
            int bestMatch = -1; 

            for (int i = 0; i < rgipesAll.Count; i++) { 

                // try for an exact match.  semantics of equals are a bit loose here...
                //
                if (gridEntry == rgipesAll[i]) { 
                    return i - GetScrollOffset();
                } 
                else if (bestMatch == -1 && gridEntry.Equals(rgipesAll[i])) { 
                    bestMatch = i - GetScrollOffset();
                } 
            }

            if (bestMatch != -1) {
                return bestMatch; 
            }
 
            return -1 - GetScrollOffset(); 
        }
 
        public virtual bool GetInPropertySet() {
            return GetFlag(FlagInPropertySet);
        }
 
        protected virtual bool GetScrollbarHidden() {
            if (scrollBar == null) { 
                return true; 
            }
            return !ScrollBar.Visible; 
        }

        /// 
        ///  
        /// Returns a string containing test info about a given GridEntry. Requires an offset into the top-level
        /// entry collection (ie. nested entries are not accessible). Or specify -1 to get info for the current 
        /// selected entry (which can be any entry, top-level or nested). 
        /// 
        public virtual string GetTestingInfo(int entry) { 
            GridEntry gridEntry = (entry < 0) ? GetGridEntryFromRow(selectedRow) : GetGridEntryFromOffset(entry);

            if (gridEntry == null)
                return ""; 
            else
                return gridEntry.GetTestingInfo(); 
        } 

        public Color GetTextColor() { 
            return this.ForeColor;
        }

        private void LayoutWindow(bool invalidate) { 
            Rectangle rect = ClientRectangle;
            Size sizeWindow = new Size(rect.Width,rect.Height); 
 
            if (scrollBar != null) {
                Rectangle boundsScroll = ScrollBar.Bounds; 
                boundsScroll.X = sizeWindow.Width - boundsScroll.Width - 1;
                boundsScroll.Y = 1;
                boundsScroll.Height = sizeWindow.Height - 2;
                ScrollBar.Bounds = boundsScroll; 
            }
 
            if (invalidate) { 
                Invalidate();
            } 
        }

        internal void InvalidateGridEntryValue(GridEntry ge) {
            int row = GetRowFromGridEntry(ge); 
            if (row != -1) {
                InvalidateRows(row, row, ROWVALUE); 
            } 
        }
 
        private void InvalidateRow(int row) {
            InvalidateRows(row, row, ROWVALUE | ROWLABEL);
        }
 

        private void InvalidateRows(int startRow, int endRow) { 
            InvalidateRows(startRow, endRow, ROWVALUE | ROWLABEL); 
        }
 
        private void InvalidateRows(int startRow, int endRow, int type) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:InvalidateRows");

            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Invalidating rows " + startRow.ToString(CultureInfo.InvariantCulture) + " through " + endRow.ToString(CultureInfo.InvariantCulture)); 
            Rectangle rect;
 
            // invalidate from the start row down 
            if (endRow == -1) {
                rect = GetRectangle(startRow, type); 
                rect.Height = (Size.Height - rect.Y) - 1;
                Invalidate(rect);
            }
            else { 
                for (int i = startRow; i <= endRow; i++) {
                    rect = GetRectangle(i, type); 
                    Invalidate(rect); 
                }
            } 
        }


        ///  
        /// 
        ///     Overridden to handle TAB key. 
        ///  
        protected override bool IsInputKey(Keys keyData) {
            switch (keyData & Keys.KeyCode) { 
                case Keys.Escape:
                case Keys.Tab:
                case Keys.F4:
                    return false; 

                case Keys.Return: 
                     if (Edit.Focused) { 
                        return false;
                     } 
                     break;
            }
            return base.IsInputKey(keyData);
        } 

        private bool IsMyChild(Control c) { 
 
            if (c == this || c == null) {
                return false; 
            }

            Control cParent = c.ParentInternal;
 
            while (cParent != null) {
                if (cParent == this) { 
                    return true; 
                }
                cParent = cParent.ParentInternal; 
            }
            return false;
        }
 
        private bool IsScrollValueValid(int newValue) {
            /*Debug.WriteLine("se.newValue = " + se.newValue.ToString()); 
            Debug.WriteLine("ScrollBar.Value = " + ScrollBar.Value.ToString()); 
            Debug.WriteLine("visibleRows = " + visibleRows.ToString());
            Debug.WriteLine("totalProps = " + totalProps.ToString()); 
            Debug.WriteLine("ScrollBar.Max = " + ScrollBar.Maximum.ToString());
            Debug.WriteLine("ScrollBar.LargeChange = " + ScrollBar.LargeChange.ToString());*/

            // is this move valid? 
            if (newValue == ScrollBar.Value ||
                newValue < 0 || 
                newValue > ScrollBar.Maximum || 
                (newValue + (ScrollBar.LargeChange-1) >= totalProps)) {
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView: move not needed, returning"); 
                return false;
            }
            return true;
        } 

        internal bool IsSiblingControl(Control c1, Control c2) { 
 
            Control parent1 = c1.ParentInternal;
            Control parent2 = c2.ParentInternal; 

            while (parent2 != null) {
                if (parent1 == parent2) {
                    return true; 
                }
                parent2 = parent2.ParentInternal; 
            } 
            return false;
        } 

        private void MoveSplitterTo(int xpos) {

            int widthPS = GetOurSize().Width; 
            int startPS = ptOurLocation.X;
            int pos = Math.Max(Math.Min(xpos,widthPS-10),GetOutlineIconSize() * 2); 
 
            int oldLabelWidth = InternalLabelWidth;
 
            labelRatio = ((double)widthPS / (double) (pos - startPS));

            SetConstants();
 
            if (selectedRow != -1) {
                // do this to move any editor we have 
                SelectRow(selectedRow); 
            }
 
            Rectangle r = ClientRectangle;

            // if we're moving to the left, just invalidate the values
            if (oldLabelWidth > InternalLabelWidth) { 
                int left = InternalLabelWidth - requiredLabelPaintMargin;
                Invalidate(new Rectangle(left, 0, Size.Width - left, Size.Height)); 
            } 
            else {
                // to the right, just invalidate from where the splitter was 
                // to the right
                r.X = oldLabelWidth - requiredLabelPaintMargin;
                r.Width -= r.X;
                Invalidate(r); 
            }
        } 
 
        private void OnBtnClick(object sender, EventArgs e) {
 
            if (GetFlag(FlagBtnLaunchedEditor)) {
                return;
            }
 
            if (sender == DialogButton && !Commit()) {
                return; 
            } 
            SetCommitError(ERROR_NONE);
 
            try {
                Commit();
                SetFlag(FlagBtnLaunchedEditor, true);
                PopupDialog(selectedRow); 
            }
            finally { 
                SetFlag(FlagBtnLaunchedEditor, false); 
            }
        } 

        private void OnBtnKeyDown(object sender, KeyEventArgs ke) {
            OnKeyDown(sender,ke);
        } 

 
        private void OnChildLostFocus(object sender, EventArgs e) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnChildLostFocus");
            OnLostFocus(null); 
        }

        protected override void OnGotFocus(EventArgs e) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnGotFocus"); 

            base.OnGotFocus(e); 
 
            if (e != null && !GetInPropertySet()) {
                if (!Commit()) { 
                    Edit.FocusInternal();
                    return;
                }
            } 

            if (selectedGridEntry != null && GetRowFromGridEntry(selectedGridEntry) != -1) { 
                selectedGridEntry.Focus = true; 
                SelectGridEntry(selectedGridEntry, false);
            } 
            else {
                SelectRow(0);
            }
 
            if (selectedGridEntry != null && selectedGridEntry.GetValueOwner() != null) {
                UpdateHelpAttributes(null, selectedGridEntry); 
            } 
        }
 
         protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.OnSysColorChange);
        } 

        protected override void OnHandleDestroyed(EventArgs e) { 
            SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.OnSysColorChange); 
            // We can leak this if we aren't disposed.
            // 
            if (toolTip != null && !RecreatingHandle) {
                toolTip.Dispose();
                toolTip = null;
            } 
            base.OnHandleDestroyed(e);
        } 
 
        /*
        public bool OnHelp() { 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null || !(Focused || Edit.Focused)) {
                return false;
            } 

            string keyword = gridEntry.HelpKeyword; 
            if (keyword != null && keyword.Length != 0) { 
                try {
                    IHelpService hsvc = GetHelpService(); 
                    if (hsvc != null) {
                        hsvc.ShowHelpFromKeyword(keyword);
                    }
                } 
                catch (Exception) {
                } 
            } 
            return true;
        } 

        // This has no effect, see VSW#470693.
        protected override void OnImeModeChanged(EventArgs e) {
            // VSW  #375530 
            // Only update edit box mode if actually out of [....] with grid's mode (to avoid re-entrancy issues)
            // 
            if (edit != null && edit.ImeMode != this.ImeMode) { 
                // URT  #51190
                // Keep the ImeMode of the property grid and edit box in step 
                //
                edit.ImeMode = this.ImeMode;
            }
            base.OnImeModeChanged(e); 
        }
       */ 
 
        private void OnListChange(object sender, EventArgs e) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnListChange"); 
            if (!DropDownListBox.InSetSelectedIndex()) {
                GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
                Edit.Text = gridEntry.GetPropertyTextValue(DropDownListBox.SelectedItem);
                Edit.FocusInternal(); 
                SelectEdit(false);
            } 
            SetFlag(FlagDropDownCommit, true); 
        }
 
        private void OnListMouseUp(object sender, MouseEventArgs me) {
            OnListClick(sender, me);
        }
 
        private void OnListClick(object sender, EventArgs e) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnListClick"); 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow); 

            if (DropDownListBox.Items.Count == 0) { 
               CommonEditorHide();
               SetCommitError(ERROR_NONE);
               SelectRow(selectedRow);
               return; 
            }
            else { 
                object value = DropDownListBox.SelectedItem; 

                // don't need the commit becuase we're committing anyway. 
                //
                SetFlag(FlagDropDownCommit, false);
                if (value != null && !CommitText((string)value)) {
                    SetCommitError(ERROR_NONE); 
                    SelectRow(selectedRow);
                } 
            } 
        }
 
        private void OnListDrawItem(object sender, DrawItemEventArgs die) {
            int index = die.Index;

            if (index < 0 || selectedGridEntry == null) { 
                return;
            } 
 
            string text = (string)DropDownListBox.Items[die.Index];
 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Drawing list item, value='" + text + "'");
            die.DrawBackground();
            die.DrawFocusRectangle();
 
            Rectangle drawBounds = die.Bounds;
            drawBounds.Y += 1; 
            drawBounds.X -= 1; 

 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            try {
                DrawValue(die.Graphics, drawBounds, drawBounds, gridEntry, gridEntry.ConvertTextToValue(text), (int)(die.State & DrawItemState.Selected) != 0, false, false, false);
            } 
            catch (FormatException ex) {
                ShowFormatExceptionMessage(gridEntry.PropertyLabel, text, ex); 
                if (DropDownListBox.IsHandleCreated) 
                    DropDownListBox.Visible = false;
            } 
        }

        private void OnListKeyDown(object sender, KeyEventArgs ke) {
            if (ke.KeyCode == Keys.Return) { 
                OnListClick(null, null);
                if (selectedGridEntry != null) { 
                    selectedGridEntry.OnValueReturnKey(); 
                }
            } 

            OnKeyDown(sender,ke);
        }
 
        protected override void OnLostFocus(EventArgs e) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnLostFocus"); 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "PropertyGridView lost focus"); 

            if (e != null) { 
                base.OnLostFocus(e);
            }
            if (this.FocusInside) {
                base.OnLostFocus(e); 
                return;
            } 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow); 
            if (gridEntry != null) {
                Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "removing gridEntry focus"); 
                gridEntry.Focus = false;;
                CommonEditorHide();
                InvalidateRow(selectedRow);
            } 
            base.OnLostFocus(e);
        } 
 
        private void OnEditChange(object sender, EventArgs e) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditChange"); 
            SetCommitError(ERROR_NONE, Edit.Focused);

            ToolTip.ToolTip = "";
            ToolTip.Visible = false; 

            if (!Edit.InSetText()) { 
                GridEntry gridEntry = GetGridEntryFromRow(selectedRow); 
                if (gridEntry != null && (gridEntry.Flags & GridEntry.FLAG_IMMEDIATELY_EDITABLE) != 0)
                    Commit(); 
            }
        }

        private void OnEditGotFocus(object sender, EventArgs e) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditGotFocus");
 
            if (!Edit.Visible) { 
                this.FocusInternal();
                return; 
            }

            switch (errorState) {
                case ERROR_MSGBOX_UP: 
                    return;
                case ERROR_THROWN: 
                    if (Edit.Visible) { 
                        Edit.HookMouseDown = true;
                    } 
                    break;
                default:
                    if (this.NeedsCommit) {
                        SetCommitError(ERROR_NONE, true); 
                    }
                    break; 
            } 

            if (selectedGridEntry != null && GetRowFromGridEntry(selectedGridEntry) != -1) { 
                Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "adding gridEntry focus");
                selectedGridEntry.Focus = true;
                InvalidateRow(selectedRow);
                (Edit.AccessibilityObject as ControlAccessibleObject).NotifyClients(AccessibleEvents.Focus); 
            }
            else { 
                SelectRow(0); 
            }
        } 
/*
        private void OnEditImeModeChanged(object sender, EventArgs e) {
            // URT  #51190
            // The property grid ImeMode tracks the ImeMode of the edit control. 
            // We require this because the first character the goes into the edit control
            // is composed while the PropertyGrid still has focus - so the ImeMode 
            // of the grid and the edit need to be the same or we get inconsistent IME composition. 
            //
            if (this.ImeMode != edit.ImeMode) { 
                this.ImeMode = edit.ImeMode;
            }
        }
*/ 
        private void OnEditKeyDown(object sender, KeyEventArgs ke) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditKeyDown"); 
            bool fAlt = ke.Alt; 
            if (!fAlt && (ke.KeyCode == Keys.Up || ke.KeyCode == Keys.Down)) {
                GridEntry gridEntry = GetGridEntryFromRow(selectedRow); 
                if (!gridEntry.Enumerable || !gridEntry.IsValueEditable) {
                    return;
                }
                object value = gridEntry.PropertyValue; 
                object[] rgvalues = gridEntry.GetPropertyValueList();
                ke.Handled = true; 
                if (rgvalues != null) { 
                    for (int i = 0; i < rgvalues.Length; i++) {
                        object rgvalue = rgvalues[i]; 
                        if (value != null && rgvalue != null && value.GetType() != rgvalue.GetType() && gridEntry.TypeConverter.CanConvertTo(gridEntry, value.GetType())) {
                            rgvalue = gridEntry.TypeConverter.ConvertTo(gridEntry, CultureInfo.CurrentCulture, rgvalue, value.GetType());
                        }
 
                        bool equal = (value == rgvalue) || (value != null && value.Equals(rgvalue));
 
                        if (!equal && value is string && rgvalue != null) { 
                            equal = 0 == String.Compare((string)value, rgvalue.ToString(), true, CultureInfo.CurrentCulture);
                        } 
                        if (equal) {
                            object valueNew = null;
                            if (ke.KeyCode == Keys.Up) {
                                if (i == 0) return; 
                                valueNew = rgvalues[i - 1];
                            } 
                            else { 
                                if (i == rgvalues.Length - 1) return;
                                valueNew = rgvalues[i + 1]; 
                            }
                            CommitValue(valueNew);
                            SelectEdit(false);
                            return; 
                        }
                    } 
                } 
            }
            // VS7 # 13336:  handle non-expand/collapse case of left & right as up & down 
            else if ((ke.KeyCode == Keys.Left || ke.KeyCode == Keys.Right) &&
                     (ke.Modifiers & ~Keys.Shift) != 0) {
                return;
            } 
            OnKeyDown(sender,ke);
        } 
 
        private void OnEditKeyPress(object sender, KeyPressEventArgs ke) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditKeyPress"); 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null)
                return;
 
            if (!gridEntry.IsTextEditable) {
                ke.Handled = FilterReadOnlyEditKeyPress(ke.KeyChar); 
            } 
        }
 

        private void OnEditLostFocus(object sender, EventArgs e) {

            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditLostFocus"); 

            // believe it or not, this can actually happen. 
            if (Edit.Focused || (errorState == ERROR_MSGBOX_UP) || (errorState == ERROR_THROWN)|| GetInPropertySet()) { 
                return;
            } 

            // check to see if the focus is on the drop down or one of it's children
            // if so, return;
            if (dropDownHolder != null && dropDownHolder.Visible) { 
                bool found = false;
                for (IntPtr hwnd = UnsafeNativeMethods.GetForegroundWindow(); 
                    hwnd != IntPtr.Zero; hwnd = UnsafeNativeMethods.GetParent(new HandleRef(null, hwnd))) { 
                    if (hwnd == dropDownHolder.Handle) {
                        found = true; 
                    }
                }
                if (found)
                    return; 
            }
 
            if (this.FocusInside) { 
               return;
            } 

            // if the focus isn't goint to a child of the view
            if (!Commit()) {
                Edit.FocusInternal(); 
                return;
            } 
            // change our focus state. 
            OnLostFocus(null);
        } 

        private void OnEditMouseDown(object sender, MouseEventArgs me) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEditMouseDown");
 
            if (!FocusInside) {
               SelectGridEntry(selectedGridEntry, false); 
            } 

            if (me.Clicks % 2 == 0) { 
                DoubleClickRow(selectedRow,false, ROWVALUE);
                Edit.SelectAll();
            }
 
            if (rowSelectTime == 0) {
                return; 
            } 

            // check if the click happened within the double click time since the row was selected. 
            // this allows the edits to be selected with two clicks instead of 3 (select row, double click).
            //
            long timeStamp = DateTime.Now.Ticks;
            int delta = (int)((timeStamp - rowSelectTime) / 10000); // make it milleseconds 

            if (delta < SystemInformation.DoubleClickTime) { 
 
                Point screenPoint = Edit.PointToScreen(new Point(me.X, me.Y));
 
                if (Math.Abs(screenPoint.X - rowSelectPos.X) < SystemInformation.DoubleClickSize.Width &&
                    Math.Abs(screenPoint.Y - rowSelectPos.Y) < SystemInformation.DoubleClickSize.Height) {
                    DoubleClickRow(selectedRow,false, ROWVALUE);
                    Edit.SendMessage(NativeMethods.WM_LBUTTONUP, 0, (int)(me.Y << 16 | (me.X & 0xFFFF))); 
                    Edit.SelectAll();
                } 
                rowSelectPos = Point.Empty; 

                rowSelectTime = 0; 
            }
        }

        private bool OnF4(Control sender) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnF4");
            if (ModifierKeys != 0) { 
                return false; 
            }
            if (sender == this || sender == this.ownerGrid) 
                F4Selection(true);
            else
                UnfocusSelection();
            return true; 
        }
 
        private bool OnEscape(Control sender) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnEscape");
            if ((ModifierKeys & (Keys.Alt | Keys.Control)) != 0) { 
                return false;
            }

            SetFlag(FlagDropDownCommit, false); 

            if (sender == Edit && Edit.Focused) { 
 
                // if we aren't in an error state, just quit
                if (errorState == ERROR_NONE) { 
                   Edit.Text = originalTextValue;
                   FocusInternal();
                   return true;
                } 

                if (this.NeedsCommit) { 
                    bool success = false; 
                    Edit.Text = originalTextValue;
                    bool needReset = true; 

                    if (selectedGridEntry != null) {

                        string curTextValue = selectedGridEntry.GetPropertyTextValue(); 
                        needReset = originalTextValue != curTextValue && !(string.IsNullOrEmpty(originalTextValue) && string.IsNullOrEmpty(curTextValue));
                    } 
 
                    if (needReset) {
                        try { 
                            success = CommitText(originalTextValue);
                        }
                        catch {
                        } 
                    }
                    else { 
                        success = true; 
                    }
 
                    // this would be an odd thing to happen, but...
                    if (!success) {
                        Edit.FocusInternal();
                        SelectEdit(false); 
                        return true;
                    } 
                } 

                SetCommitError(ERROR_NONE); 
                FocusInternal();
                return true;
            }
            else if (sender != this) { 
                CloseDropDown();
                FocusInternal(); 
            } 
            return false;
        } 

        protected override void OnKeyDown(KeyEventArgs ke) {
            OnKeyDown(this,ke);
        } 

        [ 
            SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // We want to commit empty text. 
                                                                                                        // So we don't have to localize it.
        ] 
        private void OnKeyDown(object sender, KeyEventArgs ke) {

            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null) return; 

            ke.Handled = true; 
            bool fControl = ke.Control; 
            bool fShift = ke.Shift;
            bool fBoth = fControl && fShift; 
            bool fAlt = ke.Alt;
            Keys keyCode = ke.KeyCode;
            bool fallingThorugh = false;
 
            // [....], we have to do this here because if we are
            // hosted in a non-windows forms dialog, we never get a chance to 
            // peek at the messages, we just get called, 
            // so we have to do this here...
            // 
            if (keyCode == Keys.Tab) {
                if (ProcessDialogKey(ke.KeyData)) {
                    ke.Handled = true;
                    return; 
                }
            } 
 
            // Alt-Arrow support... sigh...
            if (keyCode == Keys.Down && fAlt && DropDownButton.Visible) { 
                F4Selection(false);
                return;
            }
 
            if (keyCode == Keys.Up && fAlt && DropDownButton.Visible && (dropDownHolder != null) && dropDownHolder.Visible) {
                UnfocusSelection(); 
                return; 
            }
 
            if (ToolTip.Visible) {
                ToolTip.ToolTip = "";
            }
 

            if (fBoth || sender == this || sender == this.ownerGrid) { 
                switch (keyCode) { 
                    case Keys.Up:
                    case Keys.Down: 
                        int pos = (keyCode == Keys.Up ? selectedRow - 1 : selectedRow + 1);
                        SelectGridEntry(GetGridEntryFromRow(pos),true);
                        SetFlag(FlagNoDefault, false);
                        return; 
                    case Keys.Left:
                        if (fControl) { 
                            // move the splitter 3 pixels to the left 
                            MoveSplitterTo(InternalLabelWidth - 3);
                            return; 
                        }
                        if (gridEntry.InternalExpanded)
                            SetExpand(gridEntry,false);
                        else { 
                            // VS7 # 13336:  handle non-expand/collapse case of left & right as up & down
                            SelectGridEntry( GetGridEntryFromRow( selectedRow - 1 ), true ); 
                        } 
                        return;
                    case Keys.Right: 
                        if (fControl) {
                            // move the splitter 3 pixels to the right
                            MoveSplitterTo(InternalLabelWidth + 3);
                            return; 
                        }
                        if (gridEntry.Expandable) { 
                            if (gridEntry.InternalExpanded) { 
                                GridEntryCollection rgipes2 = gridEntry.Children;
                                SelectGridEntry(rgipes2.GetEntry(0),true); 
                            }
                            else
                                SetExpand(gridEntry,true);
                        } 
                        else {
                            // VS7 # 13336:  handle non-expand/collapse case of left & right as up & down 
                            SelectGridEntry( GetGridEntryFromRow( selectedRow + 1 ), true ); 
                        }
                        return; 
                    case Keys.Return:
                        if (gridEntry.Expandable) {
                            SetExpand(gridEntry,!gridEntry.InternalExpanded);
                        } 
                        else {
                           gridEntry.OnValueReturnKey(); 
                        } 

                        return; 
                    case Keys.Home:
                    case Keys.End:
                        GridEntryCollection rgipes = GetAllGridEntries();
                        int pos2 = (keyCode == Keys.Home ? 0 : rgipes.Count-1); 
                        SelectGridEntry(rgipes.GetEntry(pos2),true);
                        return; 
                    case Keys.Add: 
                    case Keys.Oemplus:
                    case Keys.OemMinus: 
                    case Keys.Subtract:

                        if (!gridEntry.Expandable) {
                            break; 
                        }
 
                        SetFlag(FlagIsSpecialKey, true); 
                        bool expand = (keyCode == Keys.Add || keyCode == Keys.Oemplus);
                        SetExpand(gridEntry,expand); 
                        Invalidate();
                        ke.Handled = true;
                        return;
 

                case Keys.D8: 
                        if (fShift) { 
                            goto case Keys.Multiply;
                        } 
                        break;
                case Keys.Multiply:
                        SetFlag(FlagIsSpecialKey, true);
                        RecursivelyExpand(gridEntry,true, true, MaxRecurseExpand); 
                        ke.Handled = false;
                        return; 
 

 
                    case Keys.Prior:  //PAGE_UP:
                    case Keys.Next: //PAGE_DOWN

                        bool next = (keyCode == Keys.Next); 
                        //int rowGoal = next ? visibleRows - 1 : 0;
                        int offset = next ? visibleRows - 1 : 1 - visibleRows; 
 
                        int row = selectedRow;
 
                        if (fControl && !fShift) {
                            return;
                        }
                        if (selectedRow != -1) { // actual paging. 

                            int start = GetScrollOffset(); 
                            SetScrollOffset(start + offset); 
                            SetConstants();
                            if (GetScrollOffset() != (start + offset)) { 
                                // we didn't make a full page
                                if (next) {
                                    row = visibleRows - 1;
                                } 
                                else {
                                    row = 0; 
                                } 
                            }
                        } 

                        SelectRow(row);
                        Refresh();
                        return; 

                    // Copy/paste support... 
 
                    case Keys.Insert:
                        if (fShift && !fControl && !fAlt) { 
                           fallingThorugh = true;
                           goto case Keys.V;
                        }
                        goto case Keys.C; 
                    case Keys.C:
                        // copy text in current property 
                        if (fControl && !fAlt && !fShift) { 
                           DoCopyCommand();
                           return; 
                        }
                        break;
                    case Keys.Delete:
                        // cut text in current property 
                        if (fShift && !fControl && !fAlt) {
                           fallingThorugh = true; 
                           goto case Keys.X; 
                        }
                        break; 
                    case Keys.X:
                        // cut text in current property
                        if (fallingThorugh || (fControl && !fAlt && !fShift)) {
                           Clipboard.SetDataObject(gridEntry.GetPropertyTextValue()); 
                           CommitText("");
                           return; 
                        } 
                        break;
                    case Keys.V: 
                        // paste the text
                        if (fallingThorugh || (fControl && !fAlt && !fShift)) {
                           DoPasteCommand();
                        } 
                        break;
                    case Keys.A: 
                        if (fControl && !fAlt && !fShift && Edit.Visible) { 
                           Edit.FocusInternal();
                           Edit.SelectAll(); 
                        }
                        break;
                }
            } 

            if (gridEntry != null && ke.KeyData == (Keys.C | Keys.Alt | Keys.Shift | Keys.Control)) { 
                Clipboard.SetDataObject(gridEntry.GetTestingInfo()); 
                return;
            } 

            /* [....], VS30371 -- Due to conflicts with other VS commands,
               we are removing this functionality.
 
               // Ctrl + Shift + 'X' selects the property that starts with 'X'
               if (fBoth) { 
                   // now get the array to work with. 
                   GridEntry[] rgipes = GetAllGridEntries();
                   int cLength = rgipes.Length; 

                   // now get our char.
                   string strCh = (new string(new char[] {(char)ke.KeyCode})).ToLower(CultureInfo.InvariantCulture);
 
                   int cCur = -1;
                   if (gridEntry != null) 
                       for (int i = 0; i < cLength; i++) { 
                           if (rgipes[i] == gridEntry) {
                               cCur = i; 
                               break;
                           }
                       }
 
                   cCur += 1; // this indicated where we start...
                   // find next label that starts with this letter. 
                   for (int i = 0; i < cLength; i++) { 
                       GridEntry ipeCur = rgipes[(i + cCur) % cLength];
                       if (ipeCur.PropertyLabel.ToLower(CultureInfo.InvariantCulture).StartsWith(strCh)) { 
                           if (gridEntry != ipeCur) {
                               SelectGridEntry(ipeCur,true);
                               return;
                           } 
                           break;
                       } 
                   } 
               }
            */ 

            ke.Handled = false;
            return;
        } 

        protected override void OnKeyPress(KeyPressEventArgs ke) { 
 
            bool fControl = false; //ke.getControl();
            bool fShift = false; //ke.getShift(); 
            bool fBoth = fControl && fShift;
            if (!fBoth && WillFilterKeyPress(ke.KeyChar))
                // find next property with letter typed.
                FilterKeyPress(ke.KeyChar); 
            SetFlag(FlagIsSpecialKey, false);
        } 
 
        protected override void OnMouseDown(MouseEventArgs me) {
            // check for a splitter 
            if (me.Button == MouseButtons.Left && SplitterInside(me.X,me.Y) && totalProps != 0) {
                if (!Commit()) {
                    return;
                } 

                if (me.Clicks == 2) { 
                     MoveSplitterTo(this.Width / 2); 
                     return;
                } 

                UnfocusSelection();
                SetFlag(FlagIsSplitterMove, true);
                tipInfo = -1; 
                CaptureInternal = true;
                return; 
            } 

            // are ew on a propentry? 
            Point pos = FindPosition(me.X,me.Y);

            if (pos == InvalidPosition) {
                return; 
            }
 
            // Notify that prop entry of the click...but normalize 
            // it's coords first...we really  just need the x, y
            GridEntry gridEntry = GetGridEntryFromRow(pos.Y); 

            if (gridEntry != null) {
                // get the origin of this pe
                Rectangle r = GetRectangle(pos.Y, ROWLABEL); 

                lastMouseDown = new Point(me.X, me.Y); 
 
                // offset the mouse points
                // notify the prop entry 
                if (me.Button == MouseButtons.Left) {
                    gridEntry.OnMouseClick(me.X - r.X, me.Y - r.Y, me.Clicks, me.Button);
                }
                else { 
                    SelectGridEntry(gridEntry, false);
                } 
                lastMouseDown = InvalidPosition; 
                gridEntry.Focus = true;
                SetFlag(FlagNoDefault, false); 
            }
        }

        // this will make tool tip go away. 
        protected override void OnMouseLeave(EventArgs e) {
            if (!GetFlag(FlagIsSplitterMove)) 
                Cursor = Cursors.Default; // Cursor = null;; 

            base.OnMouseLeave(e); 
        }

        protected override void OnMouseMove(MouseEventArgs me) {
            int rowMoveCur; 
            Point pt = Point.Empty;
            bool onLabel = false; 
 
            if (me == null) {
                rowMoveCur = -1; 
                pt = InvalidPosition;
            }
            else {
                pt = FindPosition(me.X,me.Y); 
                if (pt == InvalidPosition || (pt.X != ROWLABEL && pt.X != ROWVALUE)) {
                    rowMoveCur = -1; 
                    ToolTip.ToolTip = ""; 
                }
                else { 
                    rowMoveCur = pt.Y;
                    onLabel = pt.X == ROWLABEL;
                }
 
            }
 
            if (pt == InvalidPosition || me == null) { 
                return;
            } 

            if (GetFlag(FlagIsSplitterMove)) {
                MoveSplitterTo(me.X);
            } 

            if ((rowMoveCur != this.TipRow || pt.X != this.TipColumn)  && !GetFlag(FlagIsSplitterMove)) { 
                GridEntry gridItem = GetGridEntryFromRow(rowMoveCur); 
                string tip = "";
                tipInfo = -1; 

                if (gridItem != null) {
                    Rectangle itemRect = GetRectangle(pt.Y, pt.X);
                    if (onLabel && gridItem.GetLabelToolTipLocation(me.X - itemRect.X, me.Y - itemRect.Y) != InvalidPoint) { 
                        tip = gridItem.LabelToolTipText;
                        this.TipRow = rowMoveCur; 
                        this.TipColumn = pt.X; 
                    }
                    else if (!onLabel && gridItem.ValueToolTipLocation != InvalidPoint && !Edit.Focused) { 
                        if (!this.NeedsCommit) {
                           tip = gridItem.GetPropertyTextValue();
                        }
                        this.TipRow = rowMoveCur; 
                        this.TipColumn = pt.X;
                    } 
                } 

                // VSWhidbey 94890: Ensure that tooltips don't display when host application is not foreground app. 
                // Assume that we don't want to display the tooltips
                IntPtr  foregroundWindow = UnsafeNativeMethods.GetForegroundWindow();
                if (UnsafeNativeMethods.IsChild(new HandleRef(null, foregroundWindow), new HandleRef(null, this.Handle))) {
                    // vs  75848 -- don't show the tips if a 
                    // dropdown is showing
                    if ((dropDownHolder == null || dropDownHolder.Component == null) || rowMoveCur == selectedRow) { 
                        ToolTip.ToolTip = tip; 
                    }
                } 
                else {
                    ToolTip.ToolTip = "";
                }
            } 

            if (totalProps != 0 && (SplitterInside(me.X,me.Y) || GetFlag(FlagIsSplitterMove))) { 
                Cursor = Cursors.VSplit; 
            }
            else { 
                Cursor = Cursors.Default; // Cursor = null;;
            }
            base.OnMouseMove(me);
        } 

        protected override void OnMouseUp(MouseEventArgs me) { 
            CancelSplitterMove(); 
        }
 
        protected override void OnMouseWheel(MouseEventArgs me) {

            this.ownerGrid.OnGridViewMouseWheel(me);
 
            HandledMouseEventArgs e = me as HandledMouseEventArgs;
            if (e != null) { 
               if (e.Handled) { 
                   return;
               } 
               e.Handled = true;
            }

            if ((ModifierKeys & (Keys.Shift | Keys.Alt)) != 0 || MouseButtons != MouseButtons.None) { 
                return; // Do not scroll when Shift or Alt key is down, or when a mouse button is down.
            } 
 
            int wheelScrollLines = SystemInformation.MouseWheelScrollLines;
            if (wheelScrollLines == 0) { 
                return; // Do not scroll when the user system setting is 0 lines per notch
            }

            Debug.Assert(this.cumulativeVerticalWheelDelta > -NativeMethods.WHEEL_DELTA, "cumulativeVerticalWheelDelta is too small"); 
            Debug.Assert(this.cumulativeVerticalWheelDelta < NativeMethods.WHEEL_DELTA, "cumulativeVerticalWheelDelta is too big");
 
            // Should this only work if the Edit has focus?  anyway 
            // we use the mouse wheel to change the values in the dropdown if it's
            // an enumerable value. 
            //
            if (selectedGridEntry != null && selectedGridEntry.Enumerable && Edit.Focused && selectedGridEntry.IsValueEditable) {
                  int index = GetCurrentValueIndex(selectedGridEntry);
                  if (index != -1) { 
                     int delta = me.Delta > 0 ? -1 : 1;
                     object[] values = selectedGridEntry.GetPropertyValueList(); 
 
                     if (delta > 0 && index >= (values.Length - 1)) {
                        index = 0; 
                     }
                     else if (delta < 0 && index == 0) {
                        index = values.Length - 1;
                     } 
                     else {
                        index += delta; 
                     } 

                     CommitValue(values[index]); 
                     SelectGridEntry(selectedGridEntry, true);
                     Edit.FocusInternal();
                     return;
                  } 
            }
 
 
            int initialOffset = GetScrollOffset();
            cumulativeVerticalWheelDelta += me.Delta; 
            float partialNotches = (float)cumulativeVerticalWheelDelta / (float)NativeMethods.WHEEL_DELTA;
            int fullNotches = (int) partialNotches;

            if (wheelScrollLines == -1) { 

               // Equivalent to large change scrolls 
               if (fullNotches != 0) { 

                    int originalOffset = initialOffset; 
            int large = fullNotches * this.scrollBar.LargeChange;
                    int newOffset = Math.Max(0,initialOffset - large);
                    newOffset = Math.Min(newOffset, totalProps - visibleRows+1);
 

                    initialOffset -= fullNotches * this.scrollBar.LargeChange; 
                    if (Math.Abs(initialOffset - originalOffset) >= Math.Abs(fullNotches * this.scrollBar.LargeChange)) { 
                        this.cumulativeVerticalWheelDelta -= fullNotches * NativeMethods.WHEEL_DELTA;
                    } 
                    else {
                        this.cumulativeVerticalWheelDelta = 0;
                    }
 
                    if (!ScrollRows(newOffset)) {
            this.cumulativeVerticalWheelDelta = 0; 
                        return; 
                    }
                } 
            }
            else {

 
                 // SystemInformation.MouseWheelScrollLines doesn't work under terminal server,
                 // it default to the notches per scroll. 
                 int scrollBands = (int) ((float) wheelScrollLines * partialNotches); 

                 if (scrollBands != 0) { 

                    if (ToolTip.Visible) {
                        ToolTip.ToolTip = "";
                    } 

                    int newOffset = Math.Max(0,initialOffset - scrollBands); 
                    newOffset = Math.Min(newOffset, totalProps - visibleRows+1); 

                    if (scrollBands > 0) { 

                        if (this.scrollBar.Value <= this.scrollBar.Minimum) {
                            this.cumulativeVerticalWheelDelta = 0;
                        } 
                        else {
                            this.cumulativeVerticalWheelDelta -= (int)((float)scrollBands  * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); 
                        } 
                    }
                    else { 

                        if (this.scrollBar.Value > (scrollBar.Maximum-visibleRows+1)) {
                            this.cumulativeVerticalWheelDelta = 0;
                        } 
                        else {
                            this.cumulativeVerticalWheelDelta -= (int)((float)scrollBands * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); 
                        } 
                    }
 
            if (!ScrollRows(newOffset)) {
            this.cumulativeVerticalWheelDelta = 0;
            return;
            } 
                }
                else { 
                    this.cumulativeVerticalWheelDelta = 0; 
                }
 
            }
        }

        protected override void OnMove(EventArgs e) { 
            CloseDropDown();
        } 
 
        protected override void OnPaintBackground(PaintEventArgs pe) {
        } 

        protected override void OnPaint(PaintEventArgs pe) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnPaint");
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "On paint called.  Rect=" + pe.ClipRectangle.ToString()); 
            Graphics g = pe.Graphics;
 
            int yPos = 0; 
            int startRow = 0;
            int endRow = visibleRows - 1; 

            Rectangle clipRect = pe.ClipRectangle;

            // give ourselves a little breathing room to account for lines, etc., as well 
            // as the entries themselves.
            // 
            clipRect.Inflate(0,2); 

            try { 
                Size sizeWindow = this.Size;

                // figure out what rows we're painting
                Point posStart = FindPosition(clipRect.X, clipRect.Y); 
                Point posEnd = FindPosition(clipRect.X, clipRect.Y + clipRect.Height);
                if (posStart != InvalidPosition) { 
                    startRow = Math.Max(0,posStart.Y); 
                }
 
                if (posEnd != InvalidPosition) {
                    endRow   = posEnd.Y;
                }
 
                int cPropsVisible = Math.Min(totalProps - GetScrollOffset(),1+visibleRows);
 
#if DEBUG 
                GridEntry debugIPEStart = GetGridEntryFromRow(startRow);
                GridEntry debugIPEEnd   = GetGridEntryFromRow(endRow); 
                string startName = debugIPEStart == null ? null : debugIPEStart.PropertyLabel;
                if (startName == null) {
                    startName = "(null)";
                } 
                string endName = debugIPEEnd == null ? null : debugIPEEnd.PropertyLabel;
                if (endName == null) { 
                    endName = "(null)"; 
                }
#endif 

                SetFlag(FlagNeedsRefresh, false);

                //SetConstants(); 

                Size size = this.GetOurSize(); 
                Point loc = this.ptOurLocation; 

                if (GetGridEntryFromRow(cPropsVisible-1) == null) { 
                    cPropsVisible--;
                }

 
                // if we actually have some properties, then start drawing the grid
                // 
                if (totalProps > 0) { 

                    // draw splitter 
                    cPropsVisible = Math.Min(cPropsVisible, endRow+1);

                    Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Drawing splitter");
                    Pen splitterPen = new Pen(ownerGrid.LineColor, GetSplitterWidth()); 
                    splitterPen.DashStyle = DashStyle.Solid;
                    g.DrawLine(splitterPen, labelWidth,loc.Y,labelWidth, (cPropsVisible)*(RowHeight+1)+loc.Y); 
                    splitterPen.Dispose(); 

                    // draw lines. 
                    Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Drawing lines");
                    Pen linePen = new Pen(g.GetNearestColor(ownerGrid.LineColor));

                    int cHeightCurRow = 0; 
                    int cLineEnd = loc.X + size.Width;
                    int cLineStart = loc.X; 
 
                    // draw values.
                    int totalWidth = GetTotalWidth() + 1; 
                    //g.TextColor = ownerGrid.TextColor;

                    // draw labels. set clip rect.
                    for (int i = startRow; i < cPropsVisible; i++) { 
                        try {
 
                            // draw the line 
                            cHeightCurRow = (i)*(RowHeight+1) + loc.Y;
                            g.DrawLine(linePen, cLineStart,cHeightCurRow,cLineEnd,cHeightCurRow); 

                            // draw the value
                            DrawValueEntry(g,i, ref clipRect);
 
                            // draw the label
                            Rectangle rect = GetRectangle(i,ROWLABEL); 
                            yPos = rect.Y + rect.Height; 
                            DrawLabel(g,i, rect, (i==selectedRow),false, ref clipRect);
                            if (i == selectedRow) { 
                                Edit.Invalidate();
                            }

                        } 
                        catch {
                            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Exception thrown during painting property " + GetGridEntryFromRow(i).PropertyLabel); 
                        } 
                    }
 
                    // draw the bottom line
                    cHeightCurRow = (cPropsVisible)*(RowHeight+1) + loc.Y;
                    g.DrawLine(linePen, cLineStart,cHeightCurRow,cLineEnd,cHeightCurRow);
 
                    linePen.Dispose();
                } 
 
                // fill anything left with window
                if (yPos < Size.Height) { 
                    yPos++;
                    Rectangle clearRect = new Rectangle(1, yPos, Size.Width - 2, Size.Height - yPos - 1);
                    Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Filling remaining area rect=" + clearRect.ToString());
 
                    g.FillRectangle(backgroundBrush, clearRect);
                } 
 
                g.DrawRectangle(SystemPens.ControlDark, 0,0,sizeWindow.Width - 1, sizeWindow.Height - 1);
 
                fontBold = null;
            }
            catch {
                Debug.Fail("Caught exception in OnPaint"); 
                // Do nothing.
            } 
            finally { 
                ClearCachedFontInfo();
            } 
        }

        private void OnGridEntryLabelDoubleClick(object s, EventArgs e) {
            GridEntry gridEntry = (GridEntry)s; 

            // if we've changed since the click (probably because we moved a row into view), bail 
            // 
            if (gridEntry != lastClickedEntry) {
                return; 
            }
            int row = GetRowFromGridEntry(gridEntry);
            DoubleClickRow(row, gridEntry.Expandable, ROWLABEL);
        } 

        private void OnGridEntryValueDoubleClick(object s, EventArgs e) { 
 
            GridEntry gridEntry = (GridEntry)s;
            // if we've changed since the click (probably because we moved a row into view), bail 
            //
            if (gridEntry != lastClickedEntry) {
                return;
            } 
            int row = GetRowFromGridEntry(gridEntry);
            DoubleClickRow(row, gridEntry.Expandable, ROWVALUE); 
        } 

        private void OnGridEntryLabelClick(object s, EventArgs e) { 
            this.lastClickedEntry = (GridEntry)s;
            SelectGridEntry(lastClickedEntry, true);
        }
 
        private void OnGridEntryOutlineClick(object s, EventArgs e) {
            GridEntry gridEntry = (GridEntry)s; 
            Debug.Assert(gridEntry.Expandable, "non-expandable IPE firing outline click"); 

            Cursor oldCursor = Cursor; 
            if (!ShouldSerializeCursor()) {
                oldCursor = null;
            }
            Cursor = Cursors.WaitCursor; 

            try { 
                SetExpand(gridEntry, !gridEntry.InternalExpanded); 
                SelectGridEntry(gridEntry, false);
            } 
            finally {
                Cursor = oldCursor;
            }
        } 

        private void OnGridEntryValueClick(object s, EventArgs e) { 
 
            this.lastClickedEntry = (GridEntry)s;
            bool setSelectTime = s != selectedGridEntry; 
            SelectGridEntry(lastClickedEntry, true);
            Edit.FocusInternal();

            if (lastMouseDown != InvalidPosition) { 

               // clear the row select time so we don't interpret this as a double click. 
               // 
               rowSelectTime = 0;
 
               Point editPoint = PointToScreen(lastMouseDown);
               editPoint = Edit.PointToClientInternal(editPoint);
               Edit.SendMessage(NativeMethods.WM_LBUTTONDOWN, 0, (int)(editPoint.Y << 16 | (editPoint.X & 0xFFFF)));
               Edit.SendMessage(NativeMethods.WM_LBUTTONUP, 0, (int)(editPoint.Y << 16 | (editPoint.X & 0xFFFF))); 
            }
 
            if (setSelectTime) { 
               rowSelectTime = DateTime.Now.Ticks;
               rowSelectPos  = PointToScreen(lastMouseDown); 
            }
            else {
               rowSelectTime = 0;
               rowSelectPos = Point.Empty; 
            }
        } 
 
        private void ClearCachedFontInfo() {
            if (baseHfont != IntPtr.Zero) { 
                SafeNativeMethods.ExternalDeleteObject(new HandleRef(this, baseHfont));
                baseHfont = IntPtr.Zero;
            }
            if (boldHfont != IntPtr.Zero) { 
                SafeNativeMethods.ExternalDeleteObject(new HandleRef(this, boldHfont));
                boldHfont = IntPtr.Zero; 
            } 
        }
 
        protected override void OnFontChanged(EventArgs e) {

            ClearCachedFontInfo();
            cachedRowHeight = -1; 

            if (this.Disposing || this.ParentInternal == null || this.ParentInternal.Disposing) { 
                return; 
            }
 
            fontBold = null;    // URT  #45662 - fontBold is cached based on Font

            ToolTip.Font = this.Font;
            SetFlag(FlagNeedUpdateUIBasedOnFont, true); 
            UpdateUIBasedOnFont(true);
            base.OnFontChanged(e); 
 
            if (selectedGridEntry != null) {
                SelectGridEntry(selectedGridEntry, true); 
            }
        }

        protected override void OnVisibleChanged(EventArgs e) { 
            if (this.Disposing || this.ParentInternal == null || this.ParentInternal.Disposing) {
                return; 
            } 

            if (this.Visible && this.ParentInternal != null) { 
                 SetConstants();
                 if (selectedGridEntry != null) {
                       SelectGridEntry(selectedGridEntry, true);
                 } 
                 if (toolTip != null) {
                     ToolTip.Font = this.Font; 
                 } 

            } 

            base.OnVisibleChanged(e);
        }
 
        // a GridEntry recreated its children
        protected virtual void OnRecreateChildren(object s, GridEntryRecreateChildrenEventArgs e) { 
            GridEntry parent = (GridEntry) s; 

            if (parent.Expanded) { 

                GridEntry[] entries = new GridEntry[allGridEntries.Count];
                allGridEntries.CopyTo(entries, 0);
 
                // find the index of the gridEntry that fired the event in our main list.
                int parentIndex = -1; 
                for (int i = 0; i < entries.Length; i++) { 
                    if (entries[i] == parent) {
                        parentIndex = i; 
                        break;
                    }
                }
 
                Debug.Assert(parentIndex != -1, "parent GridEntry not found in allGridEntries");
 
                // clear our existing handlers 
                ClearGridEntryEvents(allGridEntries, parentIndex + 1, e.OldChildCount);
 
                // resize the array if it's changed
                if (e.OldChildCount != e.NewChildCount) {
                    int newArraySize = entries.Length + (e.NewChildCount - e.OldChildCount);
                    GridEntry[] newEntries = new GridEntry[newArraySize]; 

                    // copy the existing entries up to the parent 
                    Array.Copy(entries, 0, newEntries, 0, parentIndex + 1); 

                    // copy the entries after the spot we'll be putting the new ones 
                    Array.Copy(entries, parentIndex + e.OldChildCount+1, newEntries, parentIndex + e.NewChildCount+1, entries.Length - (parentIndex + e.OldChildCount + 1));

                    entries = newEntries;
                } 

                // from that point, replace the children with tne new children. 
                GridEntryCollection children = parent.Children; 
                int childCount = children.Count;
 
                Debug.Assert(childCount == e.NewChildCount, "parent reports " + childCount + " new children, event reports " + e.NewChildCount);

                // replace the changed items
                for (int i = 0; i < childCount; i++) { 
                    entries[parentIndex + i + 1] = children.GetEntry(i);
                } 
 
                // reset the array, rehook the handlers.
                allGridEntries.Clear(); 
                allGridEntries.AddRange(entries);
                AddGridEntryEvents(allGridEntries, parentIndex + 1, childCount);

            } 

            if (e.OldChildCount != e.NewChildCount) { 
                totalProps = CountPropsFromOutline(topLevelGridEntries); 
                SetConstants();
            } 
            Invalidate();
        }

        protected override void OnResize(EventArgs e) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnResize");
 
            Rectangle newRect = ClientRectangle; 
            int       yDelta = lastClientRect == Rectangle.Empty  ? 0 : newRect.Height - lastClientRect.Height;
            bool   lastRow = (selectedRow+1) == visibleRows; 

            // if we are hiding or showing the scroll bar, update the selected row
            // or if we are changing widths
            // 
            bool sbVisible = ScrollBar.Visible;
 
            if (!lastClientRect.IsEmpty && newRect.Width > lastClientRect.Width) { 
                Rectangle rectInvalidate = new Rectangle(lastClientRect.Width-1,0,newRect.Width-lastClientRect.Width+1,lastClientRect.Height);
                Invalidate(rectInvalidate); 
            }

            if (!lastClientRect.IsEmpty && yDelta > 0) {
                Rectangle rectInvalidate = new Rectangle(0,lastClientRect.Height-1,lastClientRect.Width,newRect.Height-lastClientRect.Height+1); 
                Invalidate(rectInvalidate);
            } 
 
            int scroll = GetScrollOffset();
            SetScrollOffset(0); 
            SetConstants();
            SetScrollOffset(scroll);

 
            CommonEditorHide();
 
            LayoutWindow(false); 
            // vs  69679
            bool selectionVisible = (selectedGridEntry != null && selectedRow >=0  && selectedRow <= visibleRows); 
            SelectGridEntry(selectedGridEntry, selectionVisible);
            lastClientRect = newRect;
        }
 
        private void OnScroll(object sender, ScrollEventArgs se) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:OnScroll(" + ScrollBar.Value.ToString(CultureInfo.InvariantCulture) + " -> " + se.NewValue.ToString(CultureInfo.InvariantCulture) +")"); 
 
            if (!Commit() || !IsScrollValueValid(se.NewValue)) {
                // cancel the move 
                se.NewValue = ScrollBar.Value;
                return;
            }
 
            int oldRow = -1;
            GridEntry oldGridEntry = selectedGridEntry; 
            if (selectedGridEntry != null) { 
                oldRow = GetRowFromGridEntry(oldGridEntry);
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "OnScroll: SelectedGridEntry=" + oldGridEntry.PropertyLabel); 
            }

            ScrollBar.Value = se.NewValue;
            if (oldGridEntry != null) { 
                // we need to zero out the selected row so we don't try to commit again...since selectedRow is now bogus.
                selectedRow = -1; 
                SelectGridEntry(oldGridEntry, (ScrollBar.Value == totalProps ? true : false)); 
                int newRow = GetRowFromGridEntry(oldGridEntry);
                if (oldRow != newRow) { 
                    Invalidate();
                }
            }
            else { 
                Invalidate();
            } 
        } 

        private void OnSysColorChange(object sender, UserPreferenceChangedEventArgs e) { 
            if (e.Category == UserPreferenceCategory.Color || e.Category == UserPreferenceCategory.Accessibility) {
                SetFlag(FlagNeedUpdateUIBasedOnFont, true);
            }
        } 

        public virtual void PopupDialog(int row) { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:PopupDialog"); 
            GridEntry gridEntry = GetGridEntryFromRow(row);
            if (gridEntry != null) { 
                if (dropDownHolder != null && dropDownHolder.GetUsed()) {
                    CloseDropDown();
                    return;
                } 

                bool fBtnDropDown = gridEntry.NeedsDropDownButton; 
                bool fEnum = gridEntry.Enumerable; 
                bool fBtnDialog = gridEntry.NeedsCustomEditorButton;
                if (fEnum && !fBtnDropDown) { 
                    DropDownListBox.Items.Clear();
                    object value = gridEntry.PropertyValue;
                    object[] rgItems = gridEntry.GetPropertyValueList();
                    int maxWidth = 0; 

                    // The listbox draws with GDI, not GDI+.  So, we 
                    // use a normal DC here. 
                    //
                    IntPtr hdc = UnsafeNativeMethods.GetDC(new HandleRef(DropDownListBox, DropDownListBox.Handle)); 
                    IntPtr hFont = Font.ToHfont();
                    System.Internal.HandleCollector.Add(hFont, NativeMethods.CommonHandles.GDI);
                    NativeMethods.TEXTMETRIC tm = new NativeMethods.TEXTMETRIC();
                    int iSel = -1; 
                    try {
                        hFont = SafeNativeMethods.SelectObject(new HandleRef(DropDownListBox, hdc), new HandleRef(Font, hFont)); 
 
                        iSel = GetCurrentValueIndex(gridEntry);
                        if (rgItems != null && rgItems.Length > 0) { 
                            string s;
                            IntNativeMethods.SIZE textSize = new IntNativeMethods.SIZE();

                            for (int i = 0; i < rgItems.Length; i++) { 
                                s = gridEntry.GetPropertyTextValue(rgItems[i]);
                                DropDownListBox.Items.Add(s); 
                                IntUnsafeNativeMethods.GetTextExtentPoint32(new HandleRef(DropDownListBox, hdc), s, textSize); 
                                maxWidth = Math.Max((int) textSize.cx, maxWidth);
                            } 
                        }
                        SafeNativeMethods.GetTextMetrics(new HandleRef(DropDownListBox, hdc), ref tm);

                        // border + padding + scrollbar 
                        maxWidth += 2 + tm.tmMaxCharWidth + SystemInformation.VerticalScrollBarWidth;
 
                        hFont = SafeNativeMethods.SelectObject(new HandleRef(DropDownListBox, hdc), new HandleRef(Font, hFont)); 
                    }
                    finally { 
                        SafeNativeMethods.DeleteObject(new HandleRef(Font, hFont));
                        UnsafeNativeMethods.ReleaseDC(new HandleRef(DropDownListBox, DropDownListBox.Handle), new HandleRef(DropDownListBox, hdc));
                    }
 
                    // [....], 4/25/1998 - must check for -1 and not call the set...
                    if (iSel != -1) { 
                        DropDownListBox.SelectedIndex = iSel; 
                    }
                    SetFlag(FlagDropDownCommit, false); 
                    DropDownListBox.Height = Math.Max(tm.tmHeight + 2, Math.Min(MAX_LISTBOX_HEIGHT, DropDownListBox.PreferredHeight));
                    DropDownListBox.Width = Math.Max(maxWidth, GetRectangle(row,ROWVALUE).Width);
                    try {
                        bool resizable = DropDownListBox.Items.Count > (DropDownListBox.Height / DropDownListBox.ItemHeight); 
                        SetFlag(FlagResizableDropDown, resizable);
                        DropDownControl(DropDownListBox); 
                    } 
                    finally {
                        SetFlag(FlagResizableDropDown, false); 
                    }

                    Refresh();
                } 
                else if (fBtnDialog || fBtnDropDown) {
                     try { 
                        SetFlag(FlagInPropertySet, true); 
                        Edit.DisableMouseHook = true;
 
                        try {
                            SetFlag(FlagResizableDropDown, gridEntry.UITypeEditor.IsDropDownResizable);
                            gridEntry.EditPropertyValue(this);
                        } 
                        finally {
                            SetFlag(FlagResizableDropDown, false); 
                        } 
                     }
                     finally { 
                        SetFlag(FlagInPropertySet, false);
                        Edit.DisableMouseHook = false;
                     }
                     Refresh(); 

                     // as/urt  31468 -- we can't do this because 
                     // some dialogs are non-modal, and 
                     // this will pull focus from them.
                     // See ASURT 31468. 
                     //
                     //if (fBtnDialog) {
                     //      this.Focus();
                     //} 

                     if (FocusInside) { 
                        SelectGridEntry(gridEntry, false); 
                     }
                } 
            }
        }

        internal static void PositionTooltip(Control parent, GridToolTip ToolTip, Rectangle itemRect) { 
            ToolTip.Visible = false;
 
            NativeMethods.RECT rect = NativeMethods.RECT.FromXYWH(itemRect.X, itemRect.Y, itemRect.Width, itemRect.Height); 

            ToolTip.SendMessage(NativeMethods.TTM_ADJUSTRECT, 1, ref rect); 

            // now offset it back to screen coords
            Point locPoint = parent.PointToScreen(new Point(rect.left, rect.top));
 
            ToolTip.Location = locPoint;   // set the position once so it updates it's size with it's real width.
 
            int overHang =  (ToolTip.Location.X + ToolTip.Size.Width) - SystemInformation.VirtualScreen.Width; 
            if (overHang > 0) {
                locPoint.X -= overHang; 
                ToolTip.Location = locPoint;
            }

            // tell the control we've repositioned it. 
            ToolTip.Visible = true;
        } 
 

 
        protected override bool ProcessDialogKey(Keys keyData) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:ProcessDialogKey");
            if (HasEntries) {
                Keys keyCode = keyData & Keys.KeyCode; 
                switch (keyCode) {
                    case Keys.F4: 
                        if (FocusInside) { 
                            return OnF4(this);
                        } 
                        break;

                    case Keys.Tab:
 
                        if (((keyData & Keys.Control) != 0) ||
                            ((keyData & Keys.Alt) != 0)) { 
                            break; 
                        }
 
                        bool forward = (keyData & Keys.Shift) == 0;

                        Control focusedControl = Control.FromHandleInternal(UnsafeNativeMethods.GetFocus());
 
                        if (focusedControl == null || !IsMyChild(focusedControl)) {
                            if (forward) { 
                                TabSelection(); 
                                focusedControl = Control.FromHandleInternal(UnsafeNativeMethods.GetFocus());
                                // make sure the value actually took the focus 
                                if (IsMyChild(focusedControl)) {
                                    return true;
                                }
                                else { 
                                    return base.ProcessDialogKey(keyData);
                                } 
 
                            }
                            else { 
                                break;
                            }
                        }
                        else { 
                            // one of our editors has focus
 
                            if (Edit.Focused) { 
                                if (forward) {
                                    if (DropDownButton.Visible) { 
                                        DropDownButton.FocusInternal();
                                        return true;
                                    }
                                    else if (DialogButton.Visible) { 
                                        DialogButton.FocusInternal();
                                        return true; 
                                    } 
                                    // fall through
                                } 
                                else {
                                    SelectGridEntry(GetGridEntryFromRow(selectedRow), false);
                                    return true;
                                } 
                            }
                            else if (DialogButton.Focused || DropDownButton.Focused) { 
                                if (!forward && Edit.Visible) { 
                                    Edit.FocusInternal();
                                    return true; 
                                }
                                // fall through
                            }
                        } 
                        break;
                    case Keys.Up: 
                    case Keys.Down: 
                    case Keys.Left:
                    case Keys.Right: 
                        return false;
                    case Keys.Return:
                        if (DialogButton.Focused || DropDownButton.Focused) {
                           OnBtnClick((DialogButton.Focused ? DialogButton : DropDownButton), new EventArgs()); 
                           return true;
                        } 
                        else if (selectedGridEntry != null && selectedGridEntry.Expandable) { 
                           SetExpand(selectedGridEntry, !selectedGridEntry.InternalExpanded);
                           return true; 
                        }
                        break;
                }
            } 
            return base.ProcessDialogKey(keyData);
        } 
 
        protected virtual void RecalculateProps() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:RecalculateProps"); 
            int props = CountPropsFromOutline(topLevelGridEntries);
            if (totalProps != props) {
                totalProps = props;
                ClearGridEntryEvents(allGridEntries, 0, -1); 
                allGridEntries = null;
            } 
        } 

        internal /*public virtual*/ void RecursivelyExpand(GridEntry gridEntry, bool fInit, bool expand, int maxExpands) { 

            if (gridEntry == null || (expand && --maxExpands < 0)) {
                return;
            } 

            SetExpand(gridEntry, expand); 
 
            GridEntryCollection rgipes = gridEntry.Children;
            if (rgipes != null) 
                for (int i = 0; i < rgipes.Count; i++)
                    RecursivelyExpand(rgipes.GetEntry(i),false, expand, maxExpands);

            if (fInit) { 
                GridEntry ipeSelect = selectedGridEntry;
                Refresh(); 
                SelectGridEntry(ipeSelect,false); 
                Invalidate();
            } 

        }

        public override void Refresh() { 
            Refresh(false, -1, -1);
            // make sure we got everything 
            Invalidate(); 
        }
 
        public void Refresh(bool fullRefresh) {
            Refresh(fullRefresh, -1, -1);
        }
 

        GridPositionData positionData; 
 
        private void Refresh(bool fullRefresh, int rowStart, int rowEnd) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Refresh"); 
            Debug.WriteLineIf(GridViewDebugPaint.TraceVerbose,  "Refresh called for rows " + rowStart.ToString(CultureInfo.InvariantCulture) + " through " + rowEnd.ToString(CultureInfo.InvariantCulture));
            SetFlag(FlagNeedsRefresh, true);
            GridEntry gridEntry = null;
 
            // VSWhidbey 361345 -- there are cases here where the grid could get be disposed.
            // so just bail. 
            if (this.IsDisposed) { 
                return;
            } 

            bool pageInGridEntry = true;

            if (rowStart == -1) { 
                rowStart = 0;
            } 
 
            if (fullRefresh || this.ownerGrid.HavePropEntriesChanged()) {
                if (HasEntries && !GetInPropertySet() && !Commit()) { 
                    OnEscape(this);
                }

                int oldLength = totalProps; 
                object oldObject = topLevelGridEntries == null || topLevelGridEntries.Count == 0 ? null : ((GridEntry)topLevelGridEntries[0]).GetValueOwner();
 
                // walk up to the main IPE and refresh it. 
                if (fullRefresh) {
                    this.ownerGrid.RefreshProperties(true); 
                }

                if (oldLength > 0 && !GetFlag(FlagNoDefault)) {
                     positionData = CaptureGridPositionData(); 
                     CommonEditorHide(true);
                } 
 
                UpdateHelpAttributes(selectedGridEntry, null);
                selectedGridEntry = null; 
                SetFlag(FlagIsNewSelection, true);
                topLevelGridEntries = this.ownerGrid.GetPropEntries();

 
                ClearGridEntryEvents(allGridEntries, 0, -1);
                allGridEntries = null; 
                RecalculateProps(); 

                int newLength = totalProps; 
                if (newLength > 0) {
                    if (newLength < oldLength) {
                        SetScrollbarLength();
                        SetScrollOffset(0); 
                    }
 
                    SetConstants(); 

                    if (positionData != null) { 
                        gridEntry = positionData.Restore(this);

                        // Upon restoring the grid entry position, we don't
                        // want to page it in 
                        //
                        object newObject = topLevelGridEntries == null || topLevelGridEntries.Count == 0 ? null : ((GridEntry)topLevelGridEntries[0]).GetValueOwner(); 
                        pageInGridEntry = (gridEntry == null) || oldLength != newLength || newObject != oldObject; 
                    }
 
                    if (gridEntry == null) {
                        gridEntry = this.ownerGrid.GetDefaultGridEntry();
                        SetFlag(FlagNoDefault, gridEntry == null && totalProps > 0);
                    } 

                    InvalidateRows(rowStart, rowEnd); 
                    if (gridEntry == null) { 
                        selectedRow = 0;
                        selectedGridEntry = GetGridEntryFromRow(selectedRow); 
                    }
                }
                else if (oldLength == 0) {
                    return; 
                }
                else { 
                    SetConstants(); 
                }
 

                // Release the old positionData which contains reference to previous selected objects.
                positionData = null;
                lastClickedEntry = null; 
            }
 
            if (!HasEntries) { 
                CommonEditorHide(selectedRow != -1);
                this.ownerGrid.SetStatusBox(null, null); 
                SetScrollOffset(0);
                selectedRow = -1;
                Invalidate();
                return; 
            }
            // in case we added or removed properties 
 
            ownerGrid.ClearValueCaches();
 
            InvalidateRows(rowStart, rowEnd);

            if (gridEntry != null) {
                SelectGridEntry(gridEntry, pageInGridEntry); 
            }
        } 
 
        public virtual void Reset() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Reset"); 
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null) return;

            gridEntry.ResetPropertyValue(); 
            SelectRow(selectedRow);
        } 
 
        protected virtual void ResetOrigin(System.Drawing.Graphics g) {
            g.ResetTransform(); 
        }

        internal void RestoreHierarchyState(ArrayList expandedItems) {
            if (expandedItems == null) { 
               return;
            } 
 
            foreach(GridEntryCollection gec in expandedItems) {
               FindEquivalentGridEntry(gec); 
            }
        }

        public virtual DialogResult RunDialog(Form dialog) { 
            return ShowDialog(dialog);
        } 
 
        internal ArrayList SaveHierarchyState(GridEntryCollection entries) {
            return SaveHierarchyState(entries, null); 
        }

        private ArrayList SaveHierarchyState(GridEntryCollection entries, ArrayList expandedItems) {
            if (entries == null) { 
               return new ArrayList();
            } 
 
            if (expandedItems == null) {
               expandedItems = new ArrayList(); 
            }

            for (int i = 0; i < entries.Count; i++) {
               if (((GridEntry)entries[i]).InternalExpanded) { 
                  GridEntry entry = entries.GetEntry(i);
                  expandedItems.Add(GetGridEntryHierarchy(entry.Children.GetEntry(0))); 
                  SaveHierarchyState(entry.Children, expandedItems); 
               }
            } 

            return expandedItems;
        }
 
        // Scroll to the new offset
        private bool ScrollRows(int newOffset) { 
 
             GridEntry ipeCur = selectedGridEntry;
 
             if (!IsScrollValueValid(newOffset) || !Commit()) {
                 return false;
             }
 
             bool showEdit = Edit.Visible;
             bool showBtnDropDown = DropDownButton.Visible; 
             bool showBtnEdit     = DialogButton.Visible; 

             Edit.Visible = false; 
             DialogButton.Visible = false;
             DropDownButton.Visible = false;

             SetScrollOffset(newOffset); 

             if (ipeCur != null) { 
                int curRow = GetRowFromGridEntry(ipeCur); 
                if (curRow >=0 && curRow < visibleRows-1) {
                    Edit.Visible = showEdit; 
                    DialogButton.Visible = showBtnEdit;
                    DropDownButton.Visible = showBtnDropDown;
                    SelectGridEntry(ipeCur, true);
                } 
                else {
                    CommonEditorHide(); 
                } 
             }
             else { 
                CommonEditorHide();
             }

             Invalidate(); 
             return true;
        } 
 
        private void SelectEdit(bool caretAtEnd) {
            if (edit != null) { 
                Edit.SelectAll();
            }
        }
 
        // select functions... selectGridEntry and selectRow will select a Row
        // and install the appropriate editors. 
        // 
        internal /*protected virtual*/ void SelectGridEntry(GridEntry gridEntry, bool fPageIn) {
 
            if (gridEntry == null) return;
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:SelectGridEntry(" + gridEntry.PropertyLabel + ")");

            int row = GetRowFromGridEntry(gridEntry); 
            if (row + GetScrollOffset() < 0) {
                // throw exception? return false? 
                return; 
            }
 
            int maxRows = (int)Math.Ceiling(((double)GetOurSize().Height)/(1+RowHeight));

            // Determine whether or not we need to page-in this GridEntry
            // 

            if (!fPageIn || (row >= 0 && row < (maxRows-1))) { 
                // No need to page-in: either fPageIn is false or the row is already in view 
                //
                SelectRow(row); 
            }
            else {
                // Page-in the selected GridEntry
                // 

                selectedRow = -1; // clear the selected row since it's no longer a valid number 
 
                int cOffset = GetScrollOffset();
                if (row < 0) { 
                    SetScrollOffset(row + cOffset);
                    Invalidate();
                    SelectRow(0);
                } 
                else {
                    // try to put it one row up from the bottom 
                    int newOffset = row + cOffset - (maxRows - 2); 

                    if (newOffset >= ScrollBar.Minimum && newOffset < ScrollBar.Maximum) { 
                        SetScrollOffset(newOffset);
                    }
                    Invalidate();
                    SelectGridEntry(gridEntry, false); 
                }
            } 
        } 

        private void SelectRow(int row) { 

            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:SelectRow(" + row.ToString(CultureInfo.InvariantCulture) + ")");

            if (!GetFlag(FlagIsNewSelection)) { 
                if (this.FocusInside) {
                    // If we're in an error state, we want to bail out of this. 
                    if (errorState != ERROR_NONE || (row != selectedRow && !Commit())) { 
                        return;
                    } 
                }
                else {
                    FocusInternal();
                } 
            }
 
            GridEntry gridEntry = GetGridEntryFromRow(row); 

            // Update our reset command. 
            //
            if (row != selectedRow) {
                UpdateResetCommand(gridEntry);
            } 

            if (GetFlag(FlagIsNewSelection) && GetGridEntryFromRow(selectedRow) == null) { 
                CommonEditorHide(); 
            }
 
            UpdateHelpAttributes(selectedGridEntry, gridEntry);

            // tell the old selection it's not focused any more
            if (selectedGridEntry != null) { 
                selectedGridEntry.Focus = false;
            } 
 
            // selection not visible.
            if (row < 0 || row >= visibleRows) { 
                CommonEditorHide();
                selectedRow = row;
                selectedGridEntry = gridEntry;
                Refresh(); 
                return;
            } 
 
            // leave current selection.
            if (gridEntry == null) 
                return;

            bool newRow = false;
            int oldSel = selectedRow; 
            if (selectedRow != row || !gridEntry.Equals(selectedGridEntry)) {
                CommonEditorHide(); 
                newRow = true; 
            }
 
            if (!newRow)
                CloseDropDown();

            Rectangle rect = GetRectangle(row,ROWVALUE); 
            string s = gridEntry.GetPropertyTextValue();
 
            // what components are we using? 
            bool fBtnDropDown = gridEntry.NeedsDropDownButton | gridEntry.Enumerable;
            bool fBtnDialog = gridEntry.NeedsCustomEditorButton; 
            bool fEdit = gridEntry.IsTextEditable;
            bool fPaint = gridEntry.IsCustomPaint;

            rect.X += 1; 
            rect.Width -= 1;
 
            // we want to allow builders on read-only properties 
            if ((fBtnDialog || fBtnDropDown) && !gridEntry.ShouldRenderReadOnly && FocusInside) {
                Control btn = fBtnDropDown ? (Control)DropDownButton : (Control)DialogButton; 
                Size sizeBtn = new Size(SystemInformation.VerticalScrollBarArrowHeight, RowHeight);
                Rectangle rectTarget = new Rectangle(rect.X+rect.Width-sizeBtn.Width,
                                                      rect.Y,
                                                      sizeBtn.Width,rect.Height); 
                CommonEditorUse(btn,rectTarget);
                sizeBtn = btn.Size; 
                rect.Width -= (sizeBtn.Width); 
                btn.Invalidate();
            } 

            // if we're painting the value, size the rect between the button and the painted value
            if (fPaint) {
                rect.X += PAINT_INDENT + 1; 
                rect.Width -= PAINT_INDENT + 1;
            } 
            else { 
                rect.X += EDIT_INDENT + 1; // +1 to compensate for where GDI+ draws it's string relative to the rect.
                rect.Width -= EDIT_INDENT + 1; 
            }

            if ((GetFlag(FlagIsNewSelection) || !Edit.Focused) && (s != null && !s.Equals(Edit.Text))) {
                Edit.Text = s; 
                originalTextValue = s;
                Edit.SelectionStart = 0; 
                Edit.SelectionLength = 0; 
            }
            Edit.AccessibleName = gridEntry.Label; 

#if true // RENDERMODE
            switch (inheritRenderMode) {
                case RENDERMODE_BOLD: 
                    if (gridEntry.ShouldSerializePropertyValue()) {
                        Edit.Font = GetBoldFont(); 
                    } 
                    else {
                        Edit.Font = Font; 
                    }
                    break;
                case RENDERMODE_LEFTDOT:
                    if (gridEntry.ShouldSerializePropertyValue()) { 
                        rect.X += (LEFTDOT_SIZE * 2);
                        rect.Width -= (LEFTDOT_SIZE * 2); 
                    } 
                    // nothing
                    break; 
                case RENDERMODE_TRIANGLE:
                    // nothing
                    break;
            } 
#endif
 
            if (GetFlag(FlagIsSplitterMove) || !gridEntry.HasValue || !FocusInside) { 
                Edit.Visible = false;
            } 
            else {
                rect.Offset(1,1);
                rect.Height -= 1;
                rect.Width -= 1; 
                CommonEditorUse(Edit,rect);
                bool drawReadOnly = gridEntry.ShouldRenderReadOnly; 
                Edit.ForeColor = drawReadOnly ? this.GrayTextColor : this.ForeColor; 
                Edit.BackColor = this.BackColor;
                Edit.ReadOnly = drawReadOnly || !gridEntry.IsTextEditable; 
                Edit.UseSystemPasswordChar = gridEntry.ShouldRenderPassword;
            }

            GridEntry oldSelectedGridEntry = selectedGridEntry; 
            selectedRow = row;
            selectedGridEntry = gridEntry; 
            this.ownerGrid.SetStatusBox(gridEntry.PropertyLabel,gridEntry.PropertyDescription); 

            // tell the new focused item that it now has focus 
            if (selectedGridEntry != null) {
                selectedGridEntry.Focus = this.FocusInside;
            }
 
            if (!GetFlag(FlagIsNewSelection)) {
                FocusInternal(); 
            } 

            // 

            InvalidateRow(oldSel);

            InvalidateRow(row); 
            if (FocusInside)
            { 
                SetFlag(FlagIsNewSelection, false); 
            }
 
            try {
                if (selectedGridEntry != oldSelectedGridEntry) {
                    this.ownerGrid.OnSelectedGridItemChanged(oldSelectedGridEntry, selectedGridEntry);
                } 
            }
            catch { 
            } 
        }
 
        public virtual void SetConstants() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:SetConstants");
            Size size = this.GetOurSize();
 
            visibleRows = (int)Math.Ceiling(((double)size.Height)/(1+RowHeight));
 
            size = this.GetOurSize(); 

            if (size.Width >= 0) { 
                labelRatio = Math.Max(Math.Min(labelRatio, 9), 1.1);
                labelWidth = ptOurLocation.X + (int) ((double)size.Width / labelRatio);
            }
 
            int oldWidth = labelWidth;
 
 
            bool adjustWidth = SetScrollbarLength();
            GridEntryCollection rgipesAll = GetAllGridEntries(); 
            if (rgipesAll != null) {
                int scroll = GetScrollOffset();
                if ((scroll + visibleRows) >= rgipesAll.Count) {
                    visibleRows = rgipesAll.Count - scroll; 
                }
            } 
 

            if (adjustWidth && size.Width >= 0) { 
                labelRatio = ((double) GetOurSize().Width / (double) (oldWidth - ptOurLocation.X));
                //labelWidth = loc.X + (int) ((double)size.Width / labelRatio);
            }
 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tsize       :" + size.ToString());
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tlocation   :" + ptOurLocation.ToString()); 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tvisibleRows:" + (visibleRows).ToString(CultureInfo.InvariantCulture)); 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tlabelWidth :" + (labelWidth).ToString(CultureInfo.InvariantCulture));
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tlabelRatio :" + (labelRatio).ToString(CultureInfo.InvariantCulture)); 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\trowHeight  :" + (RowHeight).ToString(CultureInfo.InvariantCulture));
#if DEBUG
            if (rgipesAll == null) {
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tIPE Count  :(null)"); 
            }
            else { 
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "\tIPE Count  :" + (rgipesAll.Count).ToString(CultureInfo.InvariantCulture)); 
            }
#endif 
        }

        private void SetCommitError(short error) {
            SetCommitError(error, error == ERROR_THROWN); 
        }
 
        private void SetCommitError(short error, bool capture) { 
        #if DEBUG
            if (CompModSwitches.DebugGridView.TraceVerbose) { 
                string err = "UNKNOWN!";
                switch (error) {
                    case ERROR_NONE:
                        err = "ERROR_NONE"; 
                        break;
                    case ERROR_THROWN: 
                        err = "ERROR_THROWN"; 
                        break;
                    case ERROR_MSGBOX_UP: 
                        err = "ERROR_MSGBOX_UP";
                        break;
                }
                Debug.WriteLine( "PropertyGridView:SetCommitError(error=" + err + ", capture=" + capture.ToString() + ")"); 
            }
        #endif 
            errorState = error; 
            if (error != ERROR_NONE) {
                CancelSplitterMove(); 
            }

            Edit.HookMouseDown = capture;
 
        }
 
        internal /*public virtual*/ void SetExpand(GridEntry gridEntry, bool value) { 
            if (gridEntry != null && gridEntry.Expandable) {
 
                int row = GetRowFromGridEntry(gridEntry);
                int countFromEnd = visibleRows - row;
                int curRow = selectedRow;
 
                // if the currently selected row is below us, we need to commit now
                // or the offsets will be wrong 
                if (selectedRow != -1 && row < selectedRow && Edit.Visible) { 
                    // this will cause the commit
                    FocusInternal(); 

                }

                int offset = GetScrollOffset(); 
                int items = totalProps;
 
                gridEntry.InternalExpanded = value; 
                RecalculateProps();
                GridEntry ipeSelect = selectedGridEntry; 
                if (!value) {
                    for (GridEntry ipeCur = ipeSelect; ipeCur != null; ipeCur = ipeCur.ParentGridEntry) {
                        if (ipeCur.Equals(gridEntry)) {
                            ipeSelect = gridEntry; 
                        }
                    } 
                } 
                row = GetRowFromGridEntry(gridEntry);
 
                SetConstants();

                int newItems = totalProps - items;
 
                if (value && newItems > 0 && newItems < visibleRows && (row + (newItems)) >= visibleRows && newItems < curRow) {
                    // scroll to show the newly opened items. 
                    SetScrollOffset((totalProps - items) + offset); 
                }
 
                Invalidate();

                SelectGridEntry(ipeSelect,false);
 
                int scroll = GetScrollOffset();
                SetScrollOffset(0); 
                SetConstants(); 
                SetScrollOffset(scroll);
            } 
        }

        private void SetFlag(short flag, bool value) {
            if (value) { 
                flags = (short)((ushort)flags|(ushort)flag);
            } 
            else { 
                flags &= (short)~flag;
            } 
        }

        public virtual void SetScrollOffset(int cOffset) {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:SetScrollOffset(" + cOffset.ToString(CultureInfo.InvariantCulture) + ")"); 
            int posNew = Math.Max(0, Math.Min(totalProps - visibleRows + 1, cOffset));
            int posOld = ScrollBar.Value; 
            if (posNew != posOld && IsScrollValueValid(posNew) && visibleRows > 0) { 
                ScrollBar.Value = posNew;
                Invalidate(); 
                selectedRow = GetRowFromGridEntry(selectedGridEntry);
            }
        }
 
        // C#r
        internal virtual bool _Commit() { 
            return Commit(); 
        }
 
        private bool Commit() {

            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Commit()");
 
            if (errorState == ERROR_MSGBOX_UP) {
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Commit() returning false because an error has been thrown or we are in a property set"); 
                return false; 
            }
 
            if (!this.NeedsCommit) {
                SetCommitError(ERROR_NONE);
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:Commit() returning true because no change has been made");
                return true; 
            }
 
            if (GetInPropertySet()) { 
                return false;
            } 

            GridEntry ipeCur = GetGridEntryFromRow(selectedRow);
            if (ipeCur == null) {
                return true; 
            }
            bool success = false; 
            try { 
                success = CommitText(Edit.Text);
            } 
            finally {

                if (!success) {
                    Edit.FocusInternal(); 
                    SelectEdit(false);
                } 
                else { 
                    SetCommitError(ERROR_NONE);
                } 
            }
            return success;
        }
 
        private bool CommitValue(object value) {
            GridEntry ipeCur = selectedGridEntry; 
 
            if (selectedGridEntry == null && selectedRow != -1) {
                ipeCur = GetGridEntryFromRow(selectedRow); 
            }

            if (ipeCur == null) {
                Debug.Fail("Committing with no selected row!"); 
                return true;
            } 
 
            return CommitValue(ipeCur, value);
        } 

        internal bool CommitValue(GridEntry ipeCur, object value) {

            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CommitValue(" + (value==null ? "null" :value.ToString()) + ")"); 

            int propCount = ipeCur.ChildCount; 
            bool capture = Edit.HookMouseDown; 
            object originalValue = null;
 
            try {
                originalValue = ipeCur.PropertyValue;
            }
            catch { 
                // if the getter is failing, we still want to let
                // the set happen. 
            } 

            try { 
                try {
                    SetFlag(FlagInPropertySet, true);

                    //if this propentry is enumerable, then once a value is selected from the editor, 
                    //we'll want to close the drop down (like true/false).  Otherwise, if we're
                    //working with Anchor for ex., then we should be able to select different values 
                    //from the editor, without having it close every time. 
                    if (ipeCur != null &&
                        ipeCur.Enumerable) { 
                           CloseDropDown();
                    }

                    try { 
                        Edit.DisableMouseHook = true;
                        ipeCur.PropertyValue = value; 
                    } 
                    finally {
                        Edit.DisableMouseHook = false; 
                        Edit.HookMouseDown = capture;
                    }
                }
                catch (Exception ex) { 
                    SetCommitError(ERROR_THROWN);
                    ShowInvalidMessage(ipeCur.PropertyLabel, value, ex); 
                    return false; 
                }
            } 
            finally {
                SetFlag(FlagInPropertySet, false);
            }
 
            SetCommitError(ERROR_NONE);
 
            string text = ipeCur.GetPropertyTextValue(); 
            if (!String.Equals(text, Edit.Text)) {
                Edit.Text = text; 
                Edit.SelectionStart = 0;
                Edit.SelectionLength = 0;
            }
            originalTextValue = text; 

            // Update our reset command. 
            // 
            UpdateResetCommand(ipeCur);
 
            if (ipeCur.ChildCount != propCount) {
                ClearGridEntryEvents(allGridEntries, 0, -1);
                allGridEntries = null;
                SelectGridEntry(ipeCur, true); 
            }
 
            // in case this guy got disposed... 
            if (ipeCur.Disposed) {
                bool editfocused = (edit != null && edit.Focused); 

                // reselect the row to find the replacement.
                //
                SelectGridEntry(ipeCur, true); 
                ipeCur = selectedGridEntry;
 
                if (editfocused && edit != null) { 
                    edit.Focus();
                } 
            }

            this.ownerGrid.OnPropertyValueSet(ipeCur, originalValue);
 
            return true;
        } 
 
        private bool CommitText(string text) {
 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:CommitValue(" + (text==null ? "null" :text.ToString()) + ")");

            object value = null;
 
            GridEntry ipeCur = selectedGridEntry;
 
            if (selectedGridEntry == null && selectedRow != -1) { 
                ipeCur = GetGridEntryFromRow(selectedRow);
            } 

            if (ipeCur == null) {
                Debug.Fail("Committing with no selected row!");
                return true; 
            }
 
            try 
            {
                value = ipeCur.ConvertTextToValue(text); 
            }
            catch (Exception ex)
            {
                SetCommitError(ERROR_THROWN); 
                ShowInvalidMessage(ipeCur.PropertyLabel, text, ex);
                return false; 
            } 

            SetCommitError(ERROR_NONE); 

            return CommitValue(value);
        }
 
        internal void ReverseFocus() {
            if (selectedGridEntry == null) { 
               FocusInternal(); 
            }
            else { 
               SelectGridEntry(selectedGridEntry, true);

               if (DialogButton.Visible) {
                  DialogButton.FocusInternal(); 
               }
               else if (DropDownButton.Visible) { 
                  DropDownButton.FocusInternal(); 
               }
               else if (Edit.Visible) { 
                  Edit.SelectAll();
                  Edit.FocusInternal();
               }
            } 
        }
 
        private bool SetScrollbarLength() { 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:SetScrollBarLength");
            bool sbChange = false; 
            if (totalProps != -1) {
                if (totalProps < visibleRows) {
                    SetScrollOffset(0);
                } 
                else if (GetScrollOffset() > totalProps) {
                    SetScrollOffset((totalProps+1) - visibleRows); 
                } 

                bool fHidden = !ScrollBar.Visible; 
                if (visibleRows > 0) {
                    ScrollBar.LargeChange = visibleRows-1;
                }
                ScrollBar.Maximum = Math.Max(0,totalProps - 1); 
                if (fHidden != (totalProps < visibleRows)) {
                    sbChange = true; 
                    ScrollBar.Visible = fHidden; 
                    Size size = GetOurSize();
                    if (labelWidth != -1 && size.Width > 0) { 
                        if (labelWidth > ptOurLocation.X + size.Width) {
                            labelWidth = ptOurLocation.X + (int) ((double)size.Width / labelRatio);
                        }
                        else { 
                            labelRatio = ((double) GetOurSize().Width / (double) (labelWidth - ptOurLocation.X));
                        } 
                    } 
                    Invalidate();
                } 
            }
            return sbChange;
        }
 
        /// 
        ///  
        ///      Shows the given dialog, and returns its dialog result.  You should always 
        ///      use this method rather than showing the dialog directly, as this will
        ///      properly position the dialog and provide it a dialog owner. 
        /// 
        public DialogResult /* IWindowsFormsEditorService. */ ShowDialog(Form dialog) {
            // try to shift down if sitting right on top of existing owner.
            if (dialog.StartPosition == FormStartPosition.CenterScreen) { 
                Control topControl = this;
                if (topControl != null) { 
                    while (topControl.ParentInternal != null) { 
                        topControl = topControl.ParentInternal;
                    } 
                    if (topControl.Size.Equals(dialog.Size)) {
                        dialog.StartPosition = FormStartPosition.Manual;
                        Point location = topControl.Location;
                        // 
                        location.Offset(25, 25);
                        dialog.Location = location; 
                    } 
                }
            } 

            IntPtr priorFocus = UnsafeNativeMethods.GetFocus();

            IUIService service = (IUIService)GetService(typeof(IUIService)); 
            DialogResult result;
            if (service != null) { 
                result = service.ShowDialog(dialog); 
            }
            else { 
                result = dialog.ShowDialog(this);
            }

            if (priorFocus != IntPtr.Zero) { 
                UnsafeNativeMethods.SetFocus(new HandleRef(null, priorFocus));
            } 
 
            return result;
        } 

        private void ShowFormatExceptionMessage(string propName, object value, Exception ex)
        {
            if (value == null) 
            {
                value = "(null)"; 
            } 

            if (propName == null) 
            {
                propName = "(unknown)";
            }
 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose, "PropertyGridView:ShowFormatExceptionMessage(prop=" + propName + ")");
 
            // we have to uninstall our hook so the user can push the button! 
            bool hooked = Edit.HookMouseDown;
            Edit.DisableMouseHook = true; 
            SetCommitError(ERROR_MSGBOX_UP, false);

            // Fix for NdpWhidbey#28082: Before invoking the error dialog, flush all mouse messages in the message queue.
            // Otherwise the click that triggered the error will still be in the queue, and will get eaten by the dialog, 
            // potentially causing an accidental button click. Problem occurs because we trap clicks using a system hook,
            // which usually discards the message by returning 1 to GetMessage(). But this won't occur until after the 
            // error dialog gets closed, which is much too late. 
            NativeMethods.MSG mouseMsg = new NativeMethods.MSG();
            while (UnsafeNativeMethods.PeekMessage(ref mouseMsg, 
                                                   NativeMethods.NullHandleRef,
                                                   NativeMethods.WM_MOUSEFIRST,
                                                   NativeMethods.WM_MOUSELAST,
                                                   NativeMethods.PM_REMOVE)) 
                ;
 
            // These things are just plain useless. 
            //
            if (ex is System.Reflection.TargetInvocationException) 
            {
                ex = ex.InnerException;
            }
 
            // Try to find an exception message to display
            // 
            string exMessage = ex.Message; 

            bool revert = false; 

            while (exMessage == null || exMessage.Length == 0)
            {
                ex = ex.InnerException; 
                if (ex == null)
                { 
                    break; 
                }
                exMessage = ex.Message; 
            }

            IUIService uiSvc = (IUIService)GetService(typeof(IUIService));
 
            ErrorDialog.Message = SR.GetString(SR.PBRSFormatExceptionMessage);
            ErrorDialog.Text = SR.GetString(SR.PBRSErrorTitle); 
            ErrorDialog.Details = exMessage; 

 
            if (uiSvc != null)
            {
                revert = (DialogResult.Cancel == uiSvc.ShowDialog(ErrorDialog));
            } 
            else
            { 
                revert = (DialogResult.Cancel == this.ShowDialog(ErrorDialog)); 
            }
 
            Edit.DisableMouseHook = false;

            if (hooked)
            { 
                SelectGridEntry(selectedGridEntry, true);
            } 
            SetCommitError(ERROR_THROWN, hooked); 

            if (revert) 
            {
                OnEscape(Edit);
            }
        } 

        private void ShowInvalidMessage(string propName, object value, Exception ex) { 
 
            if (value == null) {
                value = "(null)"; 
            }

            if (propName == null) {
                propName = "(unknown)"; 
            }
 
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:ShowInvalidMessage(prop=" + propName + ")"); 

            // we have to uninstall our hook so the user can push the button! 
            bool hooked = Edit.HookMouseDown;
            Edit.DisableMouseHook = true;
            SetCommitError(ERROR_MSGBOX_UP, false);
 
            // Fix for NdpWhidbey#28082: Before invoking the error dialog, flush all mouse messages in the message queue.
            // Otherwise the click that triggered the error will still be in the queue, and will get eaten by the dialog, 
            // potentially causing an accidental button click. Problem occurs because we trap clicks using a system hook, 
            // which usually discards the message by returning 1 to GetMessage(). But this won't occur until after the
            // error dialog gets closed, which is much too late. 
            NativeMethods.MSG mouseMsg = new NativeMethods.MSG();
            while (UnsafeNativeMethods.PeekMessage(ref mouseMsg,
                                                   NativeMethods.NullHandleRef,
                                                   NativeMethods.WM_MOUSEFIRST, 
                                                   NativeMethods.WM_MOUSELAST,
                                                   NativeMethods.PM_REMOVE)) 
                ; 

            // These things are just plain useless. 
            //
            if (ex is System.Reflection.TargetInvocationException) {
                ex = ex.InnerException;
            } 

            // Try to find an exception message to display 
            // 
            string exMessage = ex.Message;
 
            bool revert = false;

            while (exMessage == null || exMessage.Length == 0) {
                ex = ex.InnerException; 
                if (ex == null) {
                    break; 
                } 
                exMessage = ex.Message;
            } 

            IUIService uiSvc = (IUIService)GetService(typeof(IUIService));

            ErrorDialog.Message = SR.GetString(SR.PBRSErrorInvalidPropertyValue); 
            ErrorDialog.Text = SR.GetString(SR.PBRSErrorTitle);
            ErrorDialog.Details = exMessage; 
 

            if (uiSvc != null) { 
                revert = (DialogResult.Cancel == uiSvc.ShowDialog(ErrorDialog));
            }
            else {
                revert = (DialogResult.Cancel == this.ShowDialog(ErrorDialog)); 
            }
 
            Edit.DisableMouseHook = false; 

            if (hooked) { 
                SelectGridEntry(selectedGridEntry, true);
            }
            SetCommitError(ERROR_THROWN, hooked);
 
            if (revert) {
                OnEscape(Edit); 
            } 
        }
 
        private bool SplitterInside(int x, int y) {
            return(Math.Abs(x - InternalLabelWidth) < 4);
        }
 
        private void TabSelection() {
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow); 
            if (gridEntry == null) 
                return;
 
            if (Edit.Visible) {
                Edit.FocusInternal();
                SelectEdit(false);
            } 
            else if (dropDownHolder != null && dropDownHolder.Visible) {
                dropDownHolder.FocusComponent(); 
                return; 
            }
            else if (currentEditor != null) { 
                currentEditor.FocusInternal();
            }

            return; 
        }
 
 
        internal void RemoveSelectedEntryHelpAttributes() {
            UpdateHelpAttributes(selectedGridEntry, null); 
        }

        private void UpdateHelpAttributes(GridEntry oldEntry, GridEntry newEntry) {
            // Update the help context with the current property 
            //
            IHelpService hsvc = GetHelpService(); 
            if (hsvc == null || oldEntry == newEntry) { 
                return;
            } 

            GridEntry temp = oldEntry;
            if (oldEntry != null && !oldEntry.Disposed) {
 

                while (temp != null) { 
                    hsvc.RemoveContextAttribute("Keyword", temp.HelpKeyword); 
                    temp = temp.ParentGridEntry;
                } 
            }

            if (newEntry != null) {
                temp = newEntry; 

                UpdateHelpAttributes(hsvc, temp, true); 
            } 
        }
 
        private void UpdateHelpAttributes(IHelpService helpSvc, GridEntry entry, bool addAsF1) {
            if (entry == null) {
               return;
            } 

            UpdateHelpAttributes(helpSvc, entry.ParentGridEntry, false); 
            string helpKeyword = entry.HelpKeyword; 
            if (helpKeyword != null) {
               helpSvc.AddContextAttribute("Keyword", helpKeyword, addAsF1 ? HelpKeywordType.F1Keyword : HelpKeywordType.GeneralKeyword); 
            }
        }

 
        private void UpdateUIBasedOnFont(bool layoutRequired) {
            if (IsHandleCreated && GetFlag(FlagNeedUpdateUIBasedOnFont)) { 
                try { 
                    if (listBox != null) {
                        DropDownListBox.ItemHeight = RowHeight + 2; 
                    }
                    if (btnDropDown != null) {
                        btnDropDown.Size = new Size(SystemInformation.VerticalScrollBarArrowHeight, RowHeight);
                        if (btnDialog != null) { 
                            DialogButton.Size = DropDownButton.Size;
                        } 
                    } 

                    if (layoutRequired) { 
                        LayoutWindow(true);
                    }
                }
                finally { 
                    SetFlag(FlagNeedUpdateUIBasedOnFont, false);
                } 
            } 
        }
 
        private bool UnfocusSelection() {
            Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "PropertyGridView:UnfocusSelection()");
            GridEntry gridEntry = GetGridEntryFromRow(selectedRow);
            if (gridEntry == null) 
                return true;
 
            bool commit = Commit(); 

            if (commit && this.FocusInside) { 
                FocusInternal();
            }
            return commit;
        } 

        private void UpdateResetCommand(GridEntry gridEntry) { 
            if (totalProps > 0) { 
                IMenuCommandService mcs = (IMenuCommandService)GetService(typeof(IMenuCommandService));
                if (mcs != null) { 
                    MenuCommand reset = mcs.FindCommand(PropertyGridCommands.Reset);
                    if (reset != null) {
                        reset.Enabled = gridEntry == null ? false : gridEntry.CanResetPropertyValue();
                    } 
                }
            } 
        } 

        // a mini version of process dialog key 
        // for responding to WM_GETDLGCODE
        internal bool WantsTab(bool forward) {
            if (forward) {
                if (this.Focused) { 
                    // we want a tab if the grid has focus and
                    // we have a button or an Edit 
                    if (DropDownButton.Visible || 
                        DialogButton.Visible ||
                        Edit.Visible) { 
                        return true;
                    }
                }
                else if (Edit.Focused && (DropDownButton.Visible || DialogButton.Visible)) { 
                    // if the Edit has focus, and we have a button, we want the tab as well
                    return true; 
                } 
                return ownerGrid.WantsTab(forward);
            } 
            else {
                if (Edit.Focused || DropDownButton.Focused || DialogButton.Focused) {
                    return true;
                } 
                return ownerGrid.WantsTab(forward);
            } 
        } 

        private unsafe bool WmNotify(ref Message m) { 
            if (m.LParam != IntPtr.Zero) {
                NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam;

                if (nmhdr->hwndFrom == ToolTip.Handle) { 
                    switch (nmhdr->code) {
                        case NativeMethods.TTN_POP: 
                            break; 
                        case NativeMethods.TTN_SHOW:
                            // we want to move the tooltip over where our text would be 
                            Point mouseLoc = Cursor.Position;

                            // convert to window coords
                            mouseLoc = this.PointToClientInternal(mouseLoc); 

                            // figure out where we are and apply the offset 
                            mouseLoc = FindPosition(mouseLoc.X, mouseLoc.Y); 

                            if (mouseLoc == InvalidPosition) { 
                                break;
                            }

                            GridEntry curEntry = GetGridEntryFromRow(mouseLoc.Y); 

                            if (curEntry == null) { 
                                break; 
                            }
 
                            // get the proper rectangle
                            Rectangle itemRect = GetRectangle(mouseLoc.Y, mouseLoc.X);
                            Point     tipPt    = Point.Empty;
 
                            // and if we need a tooltip, move the tooltip control to that point.
                            if (mouseLoc.X == ROWLABEL) { 
                                tipPt = curEntry.GetLabelToolTipLocation(mouseLoc.X - itemRect.X, mouseLoc.Y - itemRect.Y); 
                            }
                            else if (mouseLoc.X == ROWVALUE) { 
                                tipPt = curEntry.ValueToolTipLocation;
                            }
                            else {
                                break; 
                            }
 
                            if (tipPt != InvalidPoint) { 
                                itemRect.Offset(tipPt);
                                PositionTooltip(this, ToolTip, itemRect); 
                                m.Result = (IntPtr)1;
                                return true;
                            }
 
                            break;
                    } 
                } 
            }
            return false; 
        }

        protected override void WndProc(ref Message m) {
            switch (m.Msg) { 

                case NativeMethods.WM_SYSCOLORCHANGE: 
                    Invalidate(); 
                    break;
 
                    // [....] -- if we get focus in the error
                    // state, make sure we push it back to the
                    // Edit or bad bad things can happen with
                    // our state... 
                    //
                case NativeMethods.WM_SETFOCUS: 
                    if (!GetInPropertySet() && Edit.Visible && (errorState != ERROR_NONE || !Commit())) { 
                        base.WndProc(ref m);
                        Edit.FocusInternal(); 
                        return;
                    }
                    break;
 
                case NativeMethods.WM_IME_STARTCOMPOSITION:
                    Edit.FocusInternal(); 
                    Edit.Clear(); 
                    UnsafeNativeMethods.PostMessage(new HandleRef(Edit, Edit.Handle), NativeMethods.WM_IME_STARTCOMPOSITION, 0, 0);
                    return; 

                case NativeMethods.WM_IME_COMPOSITION:
                    Edit.FocusInternal();
                    UnsafeNativeMethods.PostMessage(new HandleRef(Edit, Edit.Handle), NativeMethods.WM_IME_COMPOSITION, m.WParam, m.LParam); 
                    return;
 
            case NativeMethods.WM_GETDLGCODE: 

                    int flags = NativeMethods.DLGC_WANTCHARS |  NativeMethods.DLGC_WANTARROWS; 


                    if (selectedGridEntry != null) {
                        if ((ModifierKeys & Keys.Shift) == 0) { 
                            // if we're going backwards, we don't want the tab.
                            // otherwise, we only want it if we have an edit... 
                            // 
                            if (edit.Visible) {
                                flags |= NativeMethods.DLGC_WANTTAB; 
                            }
                        }
                    }
                    m.Result = (IntPtr)(flags); 
                    return;
 
                case NativeMethods.WM_MOUSEMOVE: 

                    // check if it's the same position, of so eat the message 
                    if (unchecked( (int) (long)m.LParam) == lastMouseMove) {
                        return;
                    }
                    lastMouseMove = unchecked( (int) (long)m.LParam); 
                    break;
 
                case NativeMethods.WM_NOTIFY: 
                    if (WmNotify(ref m))
                        return; 
                    break;
                case AutomationMessages.PGM_GETSELECTEDROW:
                    m.Result = (IntPtr)GetRowFromGridEntry(selectedGridEntry);
                    return; 
                case AutomationMessages.PGM_GETVISIBLEROWCOUNT:
                    m.Result = (IntPtr)Math.Min(visibleRows, totalProps); 
                    return; 
            }
 
            base.WndProc(ref m);
        }

        private class DropDownHolder : Form, IMouseHookClient { 

            private  Control                        currentControl = null; // the control that is hosted in the holder 
            private  PropertyGridView               gridView;              // the owner gridview 
            private  MouseHook                      mouseHook;             // we use this to hook mouse downs, etc. to know when to close the dropdown.
 
            private  LinkLabel                      createNewLink = null;

            // all the resizing goo...
            // 
            private bool                            resizable       = true;  // true if we're showing the resize widget.
            private bool                            resizing        = false; // true if we're in the middle of a resize operation. 
            private  bool                           resizeUp        = false; // true if the dropdown is above the grid row, which means the resize widget is at the top. 
            private Point                           dragStart       = Point.Empty;     // the point at which the drag started to compute the delta
            private Rectangle                       dragBaseRect    = Rectangle.Empty; // the original bounds of our control. 
            private int                             currentMoveType = MoveTypeNone;    // what type of move are we processing? left, bottom, or both?

            private readonly static int             ResizeBarSize;    // the thickness of the resize bar
            private readonly static int             ResizeBorderSize; // the thickness of the 2-way resize area along the outer edge of the resize bar 
            private readonly static int             ResizeGripSize;   // the size of the 4-way resize grip at outermost corner of the resize bar
            private readonly static Size            MinDropDownSize;  // the minimum size for the control. 
            private Bitmap                          sizeGripGlyph;    // our cached size grip glyph.  Control paint only does right bottom glyphs, so we cache a mirrored one.  See GetSizeGripGlyph 

            private const int                       DropDownHolderBorder = 1; 
            private const int                       MoveTypeNone    = 0x0;
            private const int                       MoveTypeBottom	= 0x1;
            private const int                       MoveTypeLeft	= 0x2;
            private const int                       MoveTypeTop  	= 0x4; 

            static DropDownHolder() { 
                MinDropDownSize = new Size(SystemInformation.VerticalScrollBarWidth * 4, SystemInformation.HorizontalScrollBarHeight * 4); 
                ResizeGripSize = SystemInformation.HorizontalScrollBarHeight;
                ResizeBarSize = ResizeGripSize + 1; 
                ResizeBorderSize = ResizeBarSize / 2;
            }

            [ 
                SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // DropDownHolder's caption is not visible.
                                                                                                            // So we don't have to localize its text. 
            ] 
            internal DropDownHolder(PropertyGridView psheet)
            : base() { 
               this.ShowInTaskbar = false;
               this.ControlBox = false;
               this.MinimizeBox = false;
               this.MaximizeBox = false; 
               this.Text = "";
               this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 
               this.AutoScaleMode = AutoScaleMode.None; // children may scale, but we won't interfere. 
               mouseHook = new MouseHook(this, this, psheet);
               Visible = false; 
               gridView = psheet;
               this.BackColor = gridView.BackColor;
            }
 
            protected override CreateParams CreateParams {
                get { 
                    CreateParams cp = base.CreateParams; 
                    cp.ExStyle |= NativeMethods.WS_EX_TOOLWINDOW;
                    cp.Style |= NativeMethods.WS_POPUP | NativeMethods.WS_BORDER; 
                    if (OSFeature.IsPresent(SystemParameter.DropShadow)) {
                        cp.ClassStyle |= NativeMethods.CS_DROPSHADOW;
                    }
                    if (gridView != null) { 
                        cp.Parent = gridView.ParentInternal.Handle;
                    } 
                    return cp; 
                }
            } 

            private LinkLabel CreateNewLink {
                get {
                    if (this.createNewLink == null) { 
                        this.createNewLink = new LinkLabel();
                        this.createNewLink.LinkClicked += new LinkLabelLinkClickedEventHandler(OnNewLinkClicked); 
                    } 
                    return createNewLink;
                } 
            }


            public virtual bool HookMouseDown{ 
                get{
                    return mouseHook.HookMouseDown; 
                } 
                set{
                    mouseHook.HookMouseDown = value; 
                }
            }

            ///  
            /// This gets set to true if there isn't enough space below the currently selected
            /// row for the drop down, so it appears above the row.  In this case, we make the resize 
            /// grip appear at the top left. 
            /// 
            public bool ResizeUp  { 

                set {
                    if (resizeUp != value) {
 
                        // clear the glyph so we regenerate it.
                        // 
                        sizeGripGlyph = null; 
                        resizeUp = value;
 
                        if (resizable) {
                            this.DockPadding.Bottom = 0;
                            this.DockPadding.Top = 0;
                            if (value) { 
                                this.DockPadding.Top = ResizeBarSize;
                            } 
                            else { 
                                this.DockPadding.Bottom = ResizeBarSize;
                            } 
                        }
                    }
                }
            } 

 
            protected override void DestroyHandle() { 
                  mouseHook.HookMouseDown = false;
                  base.DestroyHandle(); 
            }

            protected override void Dispose(bool disposing) {
 
                if (disposing && createNewLink != null) {
                    createNewLink.Dispose(); 
                    createNewLink = null; 
                }
                base.Dispose(disposing); 
            }

            public void DoModalLoop() {
 
                // Push a modal loop.  This seems expensive, but I think it is a
                // better user model than returning from DropDownControl immediately. 
                // 
                while (this.Visible) {
                    Application.DoEventsModal(); 
                    UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 250, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE);
                }
            }
 
            public virtual Control Component {
                get { 
                    return currentControl; 
                }
            } 

            /// 
            /// Get an InstanceCreationEditor for this entry.  First, we look on the property type, and if we
            /// don't find that we'll go up to the editor type itself.  That way people can associate the InstanceCreationEditor with 
            /// the type of DropDown UIType Editor.
            /// 
            ///  
            private InstanceCreationEditor GetInstanceCreationEditor(PropertyDescriptorGridEntry entry) {
 
                if (entry == null) {
                    return null;
                }
 
                InstanceCreationEditor editor = null;
 
                // check the property type itself.  this is the default path. 
                //
                PropertyDescriptor pd = entry.PropertyDescriptor; 
                if (pd != null) {
                    editor = pd.GetEditor(typeof(InstanceCreationEditor)) as InstanceCreationEditor;
                }
 
                // now check if there is a dropdown UI type editor.  If so, use that.
                // 
                if (editor == null) { 
                    UITypeEditor ute = entry.UITypeEditor;
                    if (ute != null && ute.GetEditStyle() == UITypeEditorEditStyle.DropDown) { 
                        editor = (InstanceCreationEditor)TypeDescriptor.GetEditor(ute, typeof(InstanceCreationEditor));
                    }
                }
                return editor; 
            }
 
            ///  
            /// Get a glyph for sizing the lower left hand grip.  The code in ControlPaint only does lower-right glyphs
            /// so we do some GDI+ magic to take that glyph and mirror it.  That way we can still share the code (in case it changes for theming, etc), 
            /// not have any special cases, and possibly solve world hunger.
            /// 
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)] 
            private Bitmap GetSizeGripGlyph(Graphics g) {
                if (this.sizeGripGlyph != null) { 
                    return sizeGripGlyph; 
                }
 
                // create our drawing surface based on the current graphics context.
                //
                sizeGripGlyph = new Bitmap(ResizeGripSize, ResizeGripSize, g);		
 
                using (Graphics glyphGraphics = Graphics.FromImage(sizeGripGlyph))
                { 
                    // mirror the image around the x-axis to get a gripper handle that works 
                    // for the lower left.
                    System.Drawing.Drawing2D.Matrix m = new System.Drawing.Drawing2D.Matrix(); 

                    // basically, mirroring is just scaling by -1 on the X-axis.  So any point that's like (10, 10) goes to (-10, 10).
                    // that mirrors it, but also moves everything to the negative axis, so we just bump the whole thing over by it's width.
                    // 
                    // the +1 is because things at (0,0) stay at (0,0) since [0 * -1 = 0] so we want to get them over to the other side too.
                    // 
                    // resizeUp causes the image to also be mirrored vertically so the grip can be used as a top-left grip instead of bottom-left. 
                    //
                    m.Translate(ResizeGripSize + 1, (resizeUp ? ResizeGripSize + 1: 0));			 
                    m.Scale(-1, (resizeUp ? -1 : 1));
                    glyphGraphics.Transform = m;
                    ControlPaint.DrawSizeGrip(glyphGraphics, BackColor, 0, 0, ResizeGripSize, ResizeGripSize);
                    glyphGraphics.ResetTransform(); 

                } 
                sizeGripGlyph.MakeTransparent(BackColor); 
                return sizeGripGlyph;
            } 

            public virtual bool GetUsed() {
                return(currentControl != null);
            } 

            public virtual void FocusComponent() { 
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:FocusComponent()"); 
                if (currentControl != null && Visible) {
                    currentControl.FocusInternal(); 
                }
            }

            ///  
            ///    General purpose method, based on Control.Contains()...
            /// 
            ///    Determines whether a given window (specified using native window handle) 
            ///    is a descendant of this control. This catches both contained descendants
            ///    and 'owned' windows such as modal dialogs. Using window handles rather 
            ///    than Control objects allows it to catch un-managed windows as well.
            /// 
            private bool OwnsWindow(IntPtr hWnd) {
                while (hWnd != IntPtr.Zero) { 
                    hWnd = UnsafeNativeMethods.GetWindowLong(new HandleRef(null, hWnd), NativeMethods.GWL_HWNDPARENT);
                    if (hWnd == IntPtr.Zero) { 
                        return false; 
                    }
                    if (hWnd == this.Handle) { 
                        return true;
                    }
                }
                return false; 
            }
 
            public bool OnClickHooked() { 
                  gridView.CloseDropDownInternal(false);
                  return false; 
            }

            private void OnCurrentControlResize(object o, EventArgs e) {
                if (currentControl != null && !resizing) { 
                    int oldWidth = this.Width;
                    Size newSize = new Size(2 * DropDownHolderBorder + currentControl.Width, 2 * DropDownHolderBorder + currentControl.Height); 
                    if (resizable) { 
                        newSize.Height += ResizeBarSize;
                    } 
                    try {
                        resizing = true;
                        this.SuspendLayout();
                        this.Size = newSize; 
                    }
                    finally { 
                        resizing = false; 
                        this.ResumeLayout(false);
                    } 
                    this.Left -= (this.Width - oldWidth);
                }
            }
 

            protected override void OnLayout(LayoutEventArgs levent) { 
                try { 
                    resizing = true;
                    base.OnLayout(levent); 
                }
                finally {
                    resizing = false;
                } 

            } 
 
            private void OnNewLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
                InstanceCreationEditor ice = e.Link.LinkData as InstanceCreationEditor; 

                Debug.Assert(ice != null, "How do we have a link without the InstanceCreationEditor?");
                if (ice != null) {
                    Type createType = gridView.SelectedGridEntry.PropertyType; 
                    if (createType != null) {
 
                        gridView.CloseDropDown(); 

                        object newValue = ice.CreateInstance(gridView.SelectedGridEntry, createType); 

                        if (newValue != null) {

                            // make sure we got what we asked for. 
                            //
                            if (!createType.IsInstanceOfType(newValue)) { 
                                throw new InvalidCastException(SR.GetString(SR.PropertyGridViewEditorCreatedInvalidObject, createType)); 
                            }
 
                            gridView.CommitValue(newValue);
                        }
                    }
                } 
            }
 
            ///  
            /// Just figure out what kind of sizing we would do at a given drag location.
            ///  
            private int MoveTypeFromPoint(int x, int y)
            {
                Rectangle bGripRect = new Rectangle(0, Height - ResizeGripSize, ResizeGripSize, ResizeGripSize);
                Rectangle tGripRect = new Rectangle(0, 0, ResizeGripSize, ResizeGripSize); 

                if (!resizeUp && bGripRect.Contains(x, y)) 
                { 
                    return MoveTypeLeft | MoveTypeBottom;
                } 
                else if (resizeUp && tGripRect.Contains(x, y)) {
                    return MoveTypeLeft | MoveTypeTop;
                }
                else if (!resizeUp && Math.Abs(Height - y) < ResizeBorderSize) 
                {
                    return MoveTypeBottom;				 
                } 
                else if (resizeUp && Math.Abs(y) < ResizeBorderSize)
                { 
                    return MoveTypeTop;				
                }
                return MoveTypeNone;
            } 

            ///  
            /// Decide if we're going to be sizing at the given point, and if so, Capture and safe our current state. 
            /// 
            protected override void OnMouseDown(MouseEventArgs e) 
            {
                if (e.Button == MouseButtons.Left) {
                    this.currentMoveType = MoveTypeFromPoint(e.X, e.Y);
                    if (this.currentMoveType != MoveTypeNone) 
                    {
                        dragStart = PointToScreen(new Point(e.X, e.Y)); 
                        dragBaseRect = Bounds; 
                        Capture = true;
                    } 
                    else {
                        gridView.CloseDropDown();
                    }
                } 
                base.OnMouseDown (e);
            } 
 
            /// 
            /// Either set the cursor or do a move, depending on what our currentMoveType is/ 
            /// 
            protected override void OnMouseMove(MouseEventArgs e)
            {
                // not moving so just set the cursor. 
                //
                if (this.currentMoveType == MoveTypeNone) 
                { 
                    int cursorMoveType = MoveTypeFromPoint(e.X, e.Y);
                    switch (cursorMoveType) { 
                        case (MoveTypeLeft | MoveTypeBottom):
                            Cursor = Cursors.SizeNESW;
                            break;
                        case MoveTypeBottom: 
                        case MoveTypeTop:
                            Cursor = Cursors.SizeNS; 
                            break; 
                        case MoveTypeTop | MoveTypeLeft:
                            Cursor = Cursors.SizeNWSE; 
                            break;
                        default:
                            Cursor = null;
                            break; 
                    }
                } 
                else 
                {
                    Point dragPoint = PointToScreen(new Point(e.X, e.Y)); 
                    Rectangle newBounds = Bounds;

                    // we're in a move operation, so do the resize.
                    // 
                    if ((currentMoveType & MoveTypeBottom) == MoveTypeBottom)
                    { 
                        newBounds.Height = Math.Max(MinDropDownSize.Height, dragBaseRect.Height + (dragPoint.Y - dragStart.Y)); 
                    }
 
                    // for left and top moves, we actually have to resize and move the form simultaneously.
                    // do to that, we compute the xdelta, and apply that to the base rectangle if it's not going to
                    // make the form smaller than the minimum.
                    // 
                    if ((currentMoveType & MoveTypeTop) == MoveTypeTop)
                    { 
                        int delta = dragPoint.Y - dragStart.Y; 

                        if ((dragBaseRect.Height - delta) > MinDropDownSize.Height) 
                        {
                            newBounds.Y     = dragBaseRect.Top + delta;
                            newBounds.Height = dragBaseRect.Height - delta;
                        } 
                    }
 
                    if ((currentMoveType & MoveTypeLeft) == MoveTypeLeft) 
                    {
                        int delta = dragPoint.X - dragStart.X; 

                        if ((dragBaseRect.Width - delta) > MinDropDownSize.Width)
                        {
                            newBounds.X     = dragBaseRect.Left + delta; 
                            newBounds.Width = dragBaseRect.Width - delta;
                        } 
                    } 

                    if (newBounds != Bounds) { 
                        try {
                            resizing = true;
                            this.Bounds = newBounds;
                        } 
                        finally {
                            resizing = false; 
                        } 
                    }
 
                    // Redraw!
                    //
                    Invalidate();
                } 
                base.OnMouseMove (e);
            } 
 
            protected override void OnMouseLeave(EventArgs e)
            { 
                // just clear the cursor back to the default.
                //
                Cursor = null;
                base.OnMouseLeave (e); 
            }
 
            protected override void OnMouseUp(MouseEventArgs e) 
            {
                base.OnMouseUp (e); 

                if (e.Button == MouseButtons.Left) {

                    // reset the world. 
                    //
                    this.currentMoveType = MoveTypeNone; 
                    this.dragStart = Point.Empty; 
                    this.dragBaseRect = Rectangle.Empty;
                    this.Capture = false; 
                }
            }

            ///  
            /// Just paint and draw our glyph.
            ///  
            protected override void OnPaint(PaintEventArgs pe) 
            {
                base.OnPaint(pe); 
                if (resizable) {
                    // Draw the grip
                    Rectangle lRect = new Rectangle(0, resizeUp ? 0 : Height - ResizeGripSize, ResizeGripSize, ResizeGripSize);
                    pe.Graphics.DrawImage(GetSizeGripGlyph(pe.Graphics), lRect); 

                    // Draw the divider 
                    int y = resizeUp ? (ResizeBarSize - 1) : (Height - ResizeBarSize); 
                    Pen pen = new Pen(SystemColors.ControlDark, 1);
                    pen.DashStyle = DashStyle.Solid; 
                    pe.Graphics.DrawLine(pen, 0, y, Width, y);
                    pen.Dispose();
                }
            } 

           protected override bool ProcessDialogKey(Keys keyData) { 
                if ((keyData & (Keys.Shift | Keys.Control | Keys.Alt)) == 0) { 
                    switch (keyData & Keys.KeyCode) {
                        case Keys.Escape: 
                            gridView.OnEscape(this);
                            return true;
                        case Keys.F4:
                            gridView.F4Selection(true); 
                            return true;
                        case Keys.Return: 
                            // make sure the return gets forwarded to the control that 
                            // is being displayed
                            if (gridView.UnfocusSelection() && gridView.SelectedGridEntry != null) { 
                              gridView.SelectedGridEntry.OnValueReturnKey();
                            }
                            return true;
                    } 
                }
 
                return base.ProcessDialogKey(keyData); 
            }
 
            public void SetComponent(Control ctl, bool resizable) {

                this.resizable = resizable;
                this.Font = gridView.Font; 

                // check to see if we're going to be adding an InstanceCreationEditor 
                // 
                InstanceCreationEditor editor = (ctl == null ? null : GetInstanceCreationEditor(gridView.SelectedGridEntry as PropertyDescriptorGridEntry));
 
                // clear any existing control we have
                //
                if (currentControl != null) {
                    currentControl.Resize -= new EventHandler(this.OnCurrentControlResize); 
                    Controls.Remove(currentControl);
                    currentControl = null; 
                } 

                // remove the InstanceCreationEditor link 
                //
                if (createNewLink != null && createNewLink.Parent == this) {
                    this.Controls.Remove(createNewLink);
                } 

                // now set up the new control, top to bottom 
                // 
                if (ctl != null) {
 
                    currentControl = ctl;
                    Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:SetComponent(" + (ctl.GetType().Name) + ")");

                    this.DockPadding.All = 0; 

                    // first handle the control.  If it's a listbox, make sure it's got some height 
                    // to it. 
                    //
                    if (currentControl is GridViewListBox) { 
                        ListBox lb = (ListBox)currentControl;

                        if (lb.Items.Count == 0) {
                            lb.Height = Math.Max(lb.Height, lb.ItemHeight); 
                        }
                    } 
 
                    // Parent the control now.  That way it can inherit our
                    // font and scale itself if it wants to. 
                    try {
                        SuspendLayout();
                        Controls.Add(ctl);
 
                        Size sz = new Size(2 * DropDownHolderBorder + ctl.Width, 2 * DropDownHolderBorder + ctl.Height);
 
                        // now check for an editor, and show the link if there is one. 
                        //
                        if (editor != null) { 

                            // set up the link.
                            //
                            CreateNewLink.Text = editor.Text; 
                            CreateNewLink.Links.Clear();
                            CreateNewLink.Links.Add(0, editor.Text.Length, editor); 
 
                            // size it as close to the size of the text as possible.
                            // 
                            int linkHeight = CreateNewLink.Height;
                            using (Graphics g = gridView.CreateGraphics()) {
                                SizeF sizef = PropertyGrid.MeasureTextHelper.MeasureText(this.gridView.ownerGrid, g, editor.Text, gridView.GetBaseFont());
                                linkHeight = (int)sizef.Height; 
                            }
 
                            CreateNewLink.Height = linkHeight + DropDownHolderBorder; 

                            // add the total height plus some border 
                            sz.Height += (linkHeight + (DropDownHolderBorder * 2));
                        }

                        // finally, if we're resizable, add the space for the widget. 
                        //
                        if (resizable) { 
                            sz.Height += ResizeBarSize; 

                            // we use dockpadding to save space to draw the widget. 
                            //
                            if (resizeUp) {
                                this.DockPadding.Top = ResizeBarSize;
                            } 
                            else {
                                this.DockPadding.Bottom = ResizeBarSize; 
                            } 
                        }
 
                        // set the size stuff.
                        //
                        Size = sz;
                        ctl.Dock = DockStyle.Fill; 
                        ctl.Visible = true;
 
                        if (editor != null) { 
                            CreateNewLink.Dock = DockStyle.Bottom;
                            Controls.Add(CreateNewLink); 
                        }
                    }
                    finally {
                        ResumeLayout(true); 
                    }
 
                    // hook the resize event. 
                    //
                    currentControl.Resize += new EventHandler(this.OnCurrentControlResize); 
                }
                Enabled = currentControl != null;
            }
 
            protected override void WndProc(ref Message m) {
 
                if (m.Msg == NativeMethods.WM_ACTIVATE) { 
                    SetState(STATE_MODAL, true);
                    Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:WM_ACTIVATE()"); 
                    IntPtr activatedWindow = (IntPtr) m.LParam;
                    if (Visible && NativeMethods.Util.LOWORD(m.WParam) == NativeMethods.WA_INACTIVE && !this.OwnsWindow(activatedWindow)) {
                        gridView.CloseDropDownInternal(false);
                        return; 
                    }
 
                    // prevent the IMsoComponentManager active code from getting fired. 
                    //Active = ((int)m.WParam & 0x0000FFFF) != NativeMethods.WA_INACTIVE;
                    //return; 
                }
                else if (m.Msg == NativeMethods.WM_CLOSE) {
                    // don't let an ALT-F4 get you down
                    // 
                    if (Visible) {
                        gridView.CloseDropDown(); 
                    } 
                    return;
                } 

                base.WndProc(ref m);
            }
        } 

        private class GridViewListBox : ListBox { 
 
            internal bool fInSetSelectedIndex = false;
 
            public GridViewListBox(PropertyGridView gridView) {
                base.IntegralHeight = false;
            }
 
            protected override CreateParams CreateParams {
                get { 
                    CreateParams cp = base.CreateParams; 
                    cp.Style &= ~NativeMethods.WS_BORDER;
                    cp.ExStyle &= ~NativeMethods.WS_EX_CLIENTEDGE; 
                    return cp;
                }
            }
 
            public virtual bool InSetSelectedIndex() {
                return fInSetSelectedIndex; 
            } 

            protected override void OnSelectedIndexChanged(EventArgs e) { 
                fInSetSelectedIndex = true;
                base.OnSelectedIndexChanged(e);
                fInSetSelectedIndex = false;
            } 

        } 
 
        private class GridViewEdit : TextBox , IMouseHookClient {
 
            internal bool fInSetText = false;
            internal bool filter = false;
            internal PropertyGridView psheet = null;
            private  bool dontFocusMe = false; 
            private int   lastMove;
 
            private MouseHook mouseHook; 

            // We do this becuase the Focus call above doesn't always stick, so 
            // we make the Edit think that it doesn't have focus.  this prevents
            // ActiveControl code on the containercontrol from moving focus elsewhere
            // when the dropdown closes.
            public bool DontFocus { 
               set {
                  dontFocusMe = value; 
               } 
            }
 
            public virtual bool Filter {
                get { return filter;}

                set { 
                    this.filter = value;
                } 
            } 

            public override bool Focused { 
                get {
                    if (dontFocusMe) {
                        return false;
                    } 
                    return base.Focused;
                } 
            } 

 
            public override string Text {
                get {
                    return base.Text;
                } 
                set {
                    fInSetText = true; 
                    base.Text = value; 
                    fInSetText = false;
                } 
            }

            public bool DisableMouseHook {
 
                set {
                    mouseHook.DisableMouseHook = value; 
                } 
            }
 

            public virtual bool HookMouseDown{
                get{
                    return mouseHook.HookMouseDown; 
                }
                set{ 
                    mouseHook.HookMouseDown = value; 
                    if (value) {
                        this.FocusInternal(); 
                    }
                }
            }
 

            public GridViewEdit(PropertyGridView psheet) { 
                this.psheet = psheet; 
                mouseHook = new MouseHook(this, this, psheet);
            } 

            protected override void DestroyHandle() {
                  mouseHook.HookMouseDown = false;
                  base.DestroyHandle(); 
            }
 
            protected override void Dispose(bool disposing) { 
                if (disposing) {
                    mouseHook.Dispose(); 
                }
                base.Dispose(disposing);
            }
 
            public void FilterKeyPress(char keyChar) {
 
                if (IsInputChar(keyChar)) { 
                    this.FocusInternal();
                    this.SelectAll(); 
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), NativeMethods.WM_CHAR, (IntPtr)keyChar, IntPtr.Zero);
                }
            }
 

 
            ///  
            /// 
            ///     Overridden to handle TAB key. 
            /// 
            protected override bool IsInputKey(Keys keyData) {
                switch (keyData & Keys.KeyCode) {
                    case Keys.Escape: 
                    case Keys.Tab:
                    case Keys.F4: 
                    case Keys.F1: 
                    case Keys.Return:
                        return false; 
                }
                if (psheet.NeedsCommit) {
                    return false;
                } 
                return base.IsInputKey(keyData);
            } 
 
            /// 
            ///  
            ///     Overridden to handle TAB key.
            /// 
            protected override bool IsInputChar(char keyChar) {
                switch ((Keys)(int)keyChar) { 
                    case Keys.Tab:
                    case Keys.Return: 
                        return false; 
                }
                return base.IsInputChar(keyChar); 
            }

            protected override void OnKeyDown(KeyEventArgs ke) {
 
                // this is because on a dialog we may
                // not get a chance to pre-process 
                // 
                if (ProcessDialogKey(ke.KeyData)) {
                    ke.Handled = true; 
                    return;
                }

                base.OnKeyDown(ke); 
            }
 
            protected override void OnKeyPress(KeyPressEventArgs ke) { 
                if (!IsInputChar(ke.KeyChar)) {
                    ke.Handled = true; 
                    return;
                }
                base.OnKeyPress(ke);
            } 

            public bool OnClickHooked() { 
                 // can we commit this value? 
                 // eat the value if we failed to commit.
                 return !psheet._Commit(); 
            }

            protected override void OnMouseEnter(EventArgs e) {
               base.OnMouseEnter(e); 

               if (!this.Focused) { 
                  Graphics g = CreateGraphics(); 
                  if (psheet.SelectedGridEntry != null &&
                      ClientRectangle.Width <= psheet.SelectedGridEntry.GetValueTextWidth(this.Text, g, this.Font)) { 
                      psheet.ToolTip.ToolTip = this.PasswordProtect ? "" : this.Text;
                  }
                  g.Dispose();
               } 

            } 
 
            protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
 
                 // make sure we allow the Edit to handle ctrl-z
                 switch (keyData & Keys.KeyCode) {
                     case Keys.Z:
                     case Keys.C: 
                     case Keys.X:
                     case Keys.V: 
                        if( 
                           ((keyData & Keys.Control) != 0) &&
                           ((keyData & Keys.Shift) == 0) && 
                           ((keyData & Keys.Alt) == 0)) {
                           return false;
                        }
                        break; 

                     case Keys.A: 
                        if( 
                           ((keyData & Keys.Control) != 0) &&
                           ((keyData & Keys.Shift) == 0) && 
                           ((keyData & Keys.Alt) == 0)) {
                           SelectAll();
                           return true;
                        } 

                        break; 
 
                     case Keys.Insert:
                         if (((keyData & Keys.Alt) == 0)) { 
                             if (((keyData & Keys.Control) != 0) ^ ((keyData & Keys.Shift) == 0)) {
                                 return false;
                             }
                         } 
                         break;
 
                     case Keys.Delete: 
                         if(
                           ((keyData & Keys.Control) == 0) && 
                           ((keyData & Keys.Shift) != 0) &&
                           ((keyData & Keys.Alt) == 0)) {
                           return false;
                         } 
                         else if(
                               ((keyData & Keys.Control) == 0) && 
                               ((keyData & Keys.Shift) == 0) && 
                               ((keyData & Keys.Alt) == 0)
                                 ) 
                         {
                             // if this is just the delete key and we're on a non-text editable property that is resettable,
                             // reset it now.
                             // 
                             if (psheet.SelectedGridEntry != null && !psheet.SelectedGridEntry.Enumerable && !psheet.SelectedGridEntry.IsTextEditable && psheet.SelectedGridEntry.CanResetPropertyValue()) {
                                 object oldValue = psheet.SelectedGridEntry.PropertyValue; 
                                 psheet.SelectedGridEntry.ResetPropertyValue(); 
                                 psheet.UnfocusSelection();
                                 psheet.ownerGrid.OnPropertyValueSet(psheet.SelectedGridEntry, oldValue); 
                             }
                         }
                         break;
                 } 
                 return base.ProcessCmdKey(ref msg, keyData);
            } 
 

            ///  
            /// 
            ///      Overrides Control.ProcessDialogKey to handle the Escape and Return
            ///      keys.
            ///  
            /// 
            protected override bool ProcessDialogKey(Keys keyData) { 
 
                // We don't do anything with modified keys here.
                // 
                if ((keyData & (Keys.Shift | Keys.Control | Keys.Alt)) == 0) {
                    switch (keyData & Keys.KeyCode) {
                        case Keys.Return:
                            bool fwdReturn = !psheet.NeedsCommit; 
                            if (psheet.UnfocusSelection() && fwdReturn) {
                              psheet.SelectedGridEntry.OnValueReturnKey(); 
                            } 
                            return true;
                        case Keys.Escape: 
                            psheet.OnEscape(this);
                            return true;
                        case Keys.F4:
                            psheet.F4Selection(true); 
                            return true;
                    } 
                } 

                // for the tab key, we want to commit before we allow it to be processed. 
                if ((keyData & Keys.KeyCode) == Keys.Tab && ((keyData & (Keys.Control | Keys.Alt)) == 0)) {
                    return !psheet._Commit();
                }
 
                return base.ProcessDialogKey(keyData);
            } 
 
            protected override void SetVisibleCore(bool value) {
                Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:Visible(" + (value.ToString()) + ")"); 
                // make sure we dont' have the mouse captured if
                // we're going invisible
                if (value == false && this.HookMouseDown) {
                    mouseHook.HookMouseDown = false; 
                }
                base.SetVisibleCore(value); 
            } 

 
            // a mini version of process dialog key
            // for responding to WM_GETDLGCODE
            internal bool WantsTab(bool forward) {
                return psheet.WantsTab(forward); 
            }
 
            private unsafe bool WmNotify(ref Message m) { 

                if (m.LParam != IntPtr.Zero) { 
                   NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam;

                   if (nmhdr->hwndFrom == psheet.ToolTip.Handle) {
                       switch (nmhdr->code) { 
                          case NativeMethods.TTN_SHOW:
                             PropertyGridView.PositionTooltip(this, psheet.ToolTip, ClientRectangle); 
                             m.Result = (IntPtr)1; 
                             return true;
                          default: 
                             psheet.WndProc(ref m);
                             break;
                       }
                   } 
                }
                return false; 
            } 

            protected override void WndProc(ref Message m) { 

                if (filter) {
                    if (psheet.FilterEditWndProc(ref m)) {
                        return; 
                    }
                } 
 
                switch (m.Msg) {
                    case NativeMethods.WM_STYLECHANGED: 
                        if ((unchecked( (int) (long)m.WParam) & NativeMethods.GWL_EXSTYLE) != 0) {
                            psheet.Invalidate();
                        }
                        break; 
                    case NativeMethods.WM_MOUSEMOVE:
                        if (unchecked( (int) (long)m.LParam) == lastMove) { 
                            return; 
                        }
                        lastMove = unchecked( (int) (long)m.LParam); 
                        break;
                    case NativeMethods.WM_DESTROY:
                        mouseHook.HookMouseDown = false;
                        break; 
                    case NativeMethods.WM_SHOWWINDOW:
                        if (IntPtr.Zero == m.WParam) { 
                            mouseHook.HookMouseDown = false; 
                        }
                        break; 
                    case NativeMethods.WM_PASTE:
                        /*if (!this.ReadOnly) {
                            IDataObject dataObject = Clipboard.GetDataObject();
                            Debug.Assert(dataObject != null, "Failed to get dataObject from clipboard"); 
                            if (dataObject != null) {
                                object data = dataObject.GetData(typeof(string)); 
                                if (data != null) { 
                                    string clipboardText = data.ToString();
                                    SelectedText = clipboardText; 
                                    m.result = 1;
                                    return;
                                }
                            } 
                        }*/
                        if (this.ReadOnly) { 
                           return; 
                        }
                        break; 

                    case NativeMethods.WM_GETDLGCODE:

                        m.Result = (IntPtr)((long)m.Result | NativeMethods.DLGC_WANTARROWS | NativeMethods.DLGC_WANTCHARS); 
                        if (psheet.NeedsCommit || this.WantsTab((ModifierKeys & Keys.Shift) == 0)) {
                            m.Result = (IntPtr)((long)m.Result | NativeMethods.DLGC_WANTALLKEYS | NativeMethods.DLGC_WANTTAB); 
                        } 
                        return;
 
                    case NativeMethods.WM_NOTIFY:
                        if (WmNotify(ref m))
                            return;
                        break; 
                }
                base.WndProc(ref m); 
            } 

            public virtual bool InSetText() { 
                return fInSetText;
            }

 
        }
 
        internal interface IMouseHookClient { 

            // return true if the click is handled, false 
            // to pass it on
            bool OnClickHooked();
        }
 
        internal class MouseHook {
            private PropertyGridView gridView; 
            private Control          control; 
            private IMouseHookClient client;
 
            internal int        thisProcessID = 0;
            private GCHandle    mouseHookRoot;
            private IntPtr      mouseHookHandle = IntPtr.Zero;
            private bool        hookDisable = false; 

            private bool processing; 
 
            public MouseHook(Control control, IMouseHookClient client, PropertyGridView gridView) {
               this.control = control; 
               this.gridView = gridView;
               this.client = client;
               #if DEBUG
               callingStack = Environment.StackTrace; 
               #endif
            } 
 
            #if DEBUG
            string callingStack; 
            ~MouseHook() {
                Debug.Assert(mouseHookHandle == IntPtr.Zero, "Finalizing an active mouse hook.  This will crash the process.  Calling stack: " + callingStack);
            }
            #endif 

 
            public bool DisableMouseHook { 

                set { 
                    hookDisable = value;
                    if (value) {
                        UnhookMouse();
                    } 
                }
            } 
 

            public virtual bool HookMouseDown{ 
                get{
                    GC.KeepAlive(this);
                    return mouseHookHandle != IntPtr.Zero;
                } 
                set{
                    if (value && !hookDisable) { 
                        HookMouse(); 
                    }
                    else { 
                        UnhookMouse();
                    }
                }
            } 

 
            public void Dispose() { 
               UnhookMouse();
            } 


            /// 
            ///  
            ///     Sets up the needed windows hooks to catch messages.
            ///  
            ///  
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Process)] 
            private void HookMouse() {
                GC.KeepAlive(this);
                // Locking 'this' here is ok since this is an internal class.  See VSW#464499.
                lock(this) { 
                    if (mouseHookHandle != IntPtr.Zero) {
                        return; 
                    } 

                    if (thisProcessID == 0) { 
                        SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(control, control.Handle), out thisProcessID);
                    }

 
                    NativeMethods.HookProc hook = new NativeMethods.HookProc(new MouseHookObject(this).Callback);
                    mouseHookRoot = GCHandle.Alloc(hook); 
 
                    mouseHookHandle = UnsafeNativeMethods.SetWindowsHookEx(NativeMethods.WH_MOUSE,
                                                               hook, 
                                                               NativeMethods.NullHandleRef,
                                                               SafeNativeMethods.GetCurrentThreadId());
                    Debug.Assert(mouseHookHandle != IntPtr.Zero, "Failed to install mouse hook");
                    Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:HookMouse()"); 
                }
            } 
 
            /// 
            ///  
            ///     HookProc used for catch mouse messages.
            /// 
            /// 
            private IntPtr MouseHookProc(int nCode, IntPtr wparam, IntPtr lparam) { 
                GC.KeepAlive(this);
                if (nCode == NativeMethods.HC_ACTION) { 
                    NativeMethods.MOUSEHOOKSTRUCT mhs = (NativeMethods.MOUSEHOOKSTRUCT)UnsafeNativeMethods.PtrToStructure(lparam, typeof(NativeMethods.MOUSEHOOKSTRUCT)); 
                    if (mhs != null) {
                        switch (unchecked( (int) (long)wparam)) { 
                            case NativeMethods.WM_LBUTTONDOWN:
                            case NativeMethods.WM_MBUTTONDOWN:
                            case NativeMethods.WM_RBUTTONDOWN:
                            case NativeMethods.WM_NCLBUTTONDOWN: 
                            case NativeMethods.WM_NCMBUTTONDOWN:
                            case NativeMethods.WM_NCRBUTTONDOWN: 
                            case NativeMethods.WM_MOUSEACTIVATE: 
                                if (ProcessMouseDown(mhs.hWnd, mhs.pt_x, mhs.pt_y)) {
                                    return (IntPtr)1; 
                                }
                                break;
                        }
 
                    }
                } 
 
                return UnsafeNativeMethods.CallNextHookEx(new HandleRef(this, mouseHookHandle), nCode, wparam, lparam);
            } 

            /// 
            /// 
            ///     Removes the windowshook that was installed. 
            /// 
            ///  
            private void UnhookMouse() { 
                GC.KeepAlive(this);
                // Locking 'this' here is ok since this is an internal class.  See VSW#464499. 
                lock(this) {
                    if (mouseHookHandle != IntPtr.Zero) {
                        UnsafeNativeMethods.UnhookWindowsHookEx(new HandleRef(this, mouseHookHandle));
                        mouseHookRoot.Free(); 
                        mouseHookHandle = IntPtr.Zero;
                        Debug.WriteLineIf(CompModSwitches.DebugGridView.TraceVerbose,  "DropDownHolder:UnhookMouse()"); 
                    } 
                }
            } 

             /*
            * Here is where we force validation on any clicks outside the
            */ 
            private bool ProcessMouseDown(IntPtr hWnd, int x, int y) {
 
 
               // com+ 12678
               // if we put up the "invalid" message box, it appears this 
               // method is getting called re-entrantly when it shouldn't be.
               // this prevents us from recursing.
               //
               if (processing) { 
                  return false;
               } 
 
                IntPtr hWndAtPoint = hWnd;
                IntPtr handle = control.Handle; 
                Control ctrlAtPoint = Control.FromHandleInternal(hWndAtPoint);

                // if it's us or one of our children, just process as normal
                // 
                if (hWndAtPoint != handle && !control.Contains(ctrlAtPoint)) {
                    Debug.Assert(thisProcessID != 0, "Didn't get our process id!"); 
 
                    // make sure the window is in our process
                    int pid; 
                    SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, hWndAtPoint), out pid);

                    // if this isn't our process, unhook the mouse.
                    if (pid != thisProcessID) { 
                        this.HookMouseDown = false;
                        return false; 
                    } 

                    bool needCommit = false; 

                    // if this a sibling control (e.g. the drop down or buttons), just forward the message and skip the commit
                    needCommit = ctrlAtPoint == null ?  true : !gridView.IsSiblingControl(control, ctrlAtPoint);
 
                    try {
                       processing = true; 
 
                       if (needCommit) {
                           if (client.OnClickHooked()) { 
                               return true; // there was an error, so eat the mouse
                           }
                           /* This breaks all sorts of stuff.  Need to find a better way to do this but we can't figure
                              out the scenario this addressed. 
                           else {
                               // Returning false lets the message go to its destination.  Only 
                               // return false if there is still a mouse button down.  That might not be the 
                               // case if committing the entry opened a modal dialog.
                               // 
                               MouseButtons state = Control.MouseButtons;
                               return (int)state == 0;
                           }
                           */ 
                       }
                    } 
                    finally { 
                       processing = false;
                    } 

                    // cancel our hook at this point
                    HookMouseDown = false;
                    //gridView.UnfocusSelection(); 
                }
                return false; 
            } 

              ///  
              /// 
            ///     Forwards messageHook calls to ToolTip.messageHookProc
            /// 
            ///  
            private class MouseHookObject {
                internal WeakReference reference; 
 
                public MouseHookObject(MouseHook parent) {
                    this.reference = new WeakReference(parent, false); 
                }

                public virtual IntPtr Callback(int nCode, IntPtr wparam, IntPtr lparam) {
                    IntPtr ret = IntPtr.Zero; 
                    try {
                        MouseHook control = (MouseHook)reference.Target; 
                        if (control != null) { 
                            ret = control.MouseHookProc(nCode, wparam, lparam);
                        } 
                    }
                    catch {
                        // ignore
                    } 
                    return ret;
                } 
            } 
        }
 
        /// 
        /// 
        ///     The accessible object class for a PropertyGridView. The child accessible objects
        ///     are accessible objects corresponding to the property grid entries. 
        /// 
        [System.Runtime.InteropServices.ComVisible(true)] 
        internal class PropertyGridViewAccessibleObject : ControlAccessibleObject { 

            ///  
            /// 
            ///     Construct a PropertyGridViewAccessibleObject
            /// 
            public PropertyGridViewAccessibleObject(PropertyGridView owner) : base(owner) { 
            }
 
            public override string Name { 
                get {
                    string name = Owner.AccessibleName; 
                    if (name != null) {
                        return name;
                    }
                    else { 
                        return SR.GetString(SR.PropertyGridDefaultAccessibleName);
                    } 
                } 
            }
 
            public override AccessibleRole Role {
                get {
                    AccessibleRole role = Owner.AccessibleRole;
                    if (role != AccessibleRole.Default) { 
                        return role;
                    } 
                    else { 
                        return AccessibleRole.Table;
                    } 
                }
            }

            public AccessibleObject Next(GridEntry current) { 
                int row = ((PropertyGridView)Owner).GetRowFromGridEntry(current);
                GridEntry nextEntry = ((PropertyGridView)Owner).GetGridEntryFromRow(++row); 
                if (nextEntry != null) { 
                    return nextEntry.AccessibilityObject;
                } 
                return null;
            }

            public AccessibleObject Previous(GridEntry current) { 
                int row = ((PropertyGridView)Owner).GetRowFromGridEntry(current);
                GridEntry prevEntry = ((PropertyGridView)Owner).GetGridEntryFromRow(--row); 
                if (prevEntry != null) { 
                    return prevEntry.AccessibilityObject;
                } 
                return null;
            }

            ///  
            /// 
            ///      Get the accessible child at the given index. 
            ///      The accessible children of a PropertyGridView are accessible objects 
            ///      corresponding to the property grid entries.
            ///  
            public override AccessibleObject GetChild(int index) {

                GridEntryCollection properties = ((PropertyGridView)Owner).AccessibilityGetGridEntries();
                if (properties != null && index >= 0 && index < properties.Count) { 
                    return properties.GetEntry(index).AccessibilityObject;
                } 
                else { 
                    return null;
                } 
            }

            /// 
            ///  
            ///      Get the number of accessible children.
            ///      The accessible children of a PropertyGridView are accessible objects 
            ///      corresponding to the property grid entries. 
            /// 
            public override int GetChildCount() { 
                GridEntryCollection properties = ((PropertyGridView)Owner).AccessibilityGetGridEntries();

                if (properties != null) {
                    return properties.Count; 
                }
                else { 
                    return 0; 
                }
            } 

            /// 
            /// 
            ///      Get the accessible object for the currently focused grid entry. 
            /// 
            public override AccessibleObject GetFocused() { 
 
                GridEntry gridEntry = ((PropertyGridView)Owner).SelectedGridEntry;
                if (gridEntry != null && gridEntry.Focus) { 
                    return gridEntry.AccessibilityObject;
                }
                return null;
            } 

            ///  
            ///  
            ///      Get the accessible object for the currently selected grid entry.
            ///  
            public override AccessibleObject GetSelected() {
                GridEntry gridEntry = ((PropertyGridView)Owner).SelectedGridEntry;
                if (gridEntry != null) {
                    return gridEntry.AccessibilityObject; 
                }
                return null; 
            } 

 

            /// 
            /// 
            ///      Get the accessible child at the given screen location. 
            ///      The accessible children of a PropertyGridView are accessible objects
            ///      corresponding to the property grid entries. 
            ///  
            public override AccessibleObject HitTest(int x, int y) {
 
                // Convert to client coordinates
                //
                NativeMethods.POINT pt = new NativeMethods.POINT(x, y);
                UnsafeNativeMethods.ScreenToClient(new HandleRef(Owner, Owner.Handle), pt); 

                // Find the grid entry at the given client coordinates 
                // 
                Point pos = ((PropertyGridView)Owner).FindPosition(pt.x, pt.y);
                if (pos != PropertyGridView.InvalidPosition) { 
                    GridEntry gridEntry = ((PropertyGridView)Owner).GetGridEntryFromRow(pos.Y);
                    if (gridEntry != null) {

                        // Return the accessible object for this grid entry 
                        //
                        return gridEntry.AccessibilityObject; 
                    } 
                }
 
                // No grid entry at this point
                //
                return null;
            } 

            ///  
            ///  
            ///      Navigate to another object.
            ///  
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public override AccessibleObject Navigate(AccessibleNavigation navdir) {

                if (GetChildCount() > 0) { 
                    // We're only handling FirstChild and LastChild here
                    switch(navdir) { 
                        case AccessibleNavigation.FirstChild: 
                            return GetChild(0);
                        case AccessibleNavigation.LastChild: 
                            return GetChild(GetChildCount() - 1);
                    }
                }
                return null;    // Perform default behavior 
            }
        } 
 
        internal class GridPositionData {
 
            ArrayList expandedState;
            GridEntryCollection selectedItemTree;
            int       itemRow;
            int       itemCount; 

            public GridPositionData(PropertyGridView gridView) { 
                selectedItemTree = gridView.GetGridEntryHierarchy(gridView.selectedGridEntry); 
                expandedState = gridView.SaveHierarchyState(gridView.topLevelGridEntries);
                itemRow = gridView.selectedRow; 
                itemCount = gridView.totalProps;
            }

            public GridEntry Restore(PropertyGridView gridView) { 
                    gridView.RestoreHierarchyState(expandedState);
                    GridEntry entry = gridView.FindEquivalentGridEntry(selectedItemTree); 
 
                    if (entry != null) {
                        gridView.SelectGridEntry(entry, true); 

                        int delta = gridView.selectedRow - itemRow;
                        if (delta != 0 && gridView.ScrollBar.Visible) {
                            if (itemRow < gridView.visibleRows) { 
                                delta += gridView.GetScrollOffset();
 
                                if (delta < 0) { 
                                    delta = 0;
                                } 
                                else if (delta > gridView.ScrollBar.Maximum) {
                                    delta = gridView.ScrollBar.Maximum - 1;
                                }
                                gridView.SetScrollOffset(delta); 
                            }
 
                        } 
                    }
                    return entry; 
            }
        }
    }
} 


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