2008-02-19 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGridView.cs
index 04dde4d9ae5c1ba154c04fec2607d5c6be5ed02f..6966ef0a43536b82ca2e63e56be803fd9546388b 100644 (file)
@@ -1,5 +1,3 @@
-#define DOUBLEBUFFER
-
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com)
 //
 // Authors:
 //      Jonathan Chambers      (jonathan.chambers@ansys.com)
+//      Ivan N. Zlatev         (contact@i-nz.net)
 //
 //
 
@@ -41,44 +40,39 @@ namespace System.Windows.Forms.PropertyGridInternal {
        internal class PropertyGridView : ScrollableControl, IWindowsFormsEditorService {
 
                #region Private Members
-               private double splitter_percent = .5;
                private const int V_INDENT = 16;
-               private int row_height;
-               private int font_height_padding = 3;
+               private const int ENTRY_SPACING = 2;
                private const int RESIZE_WIDTH = 3;
                private const int BUTTON_WIDTH = 25;
+               private const int VALUE_PAINT_WIDTH = 19;
+               private const int VALUE_PAINT_INDENT = 27;
+               private double splitter_percent = .5;
+               private int row_height;
+               private int font_height_padding = 3;
                private PropertyGridTextBox grid_textbox;
-               internal PropertyGrid property_grid;
+               private PropertyGrid property_grid;
                private bool resizing_grid;
-               private int open_grid_item_count = -1;
-               private int skipped_grid_items;
                private PropertyGridDropDown dropdown_form;
                private Form dialog_form;
                private ImplicitVScrollBar vbar;
                private StringFormat string_format;
                private Font bold_font;
-#if !DOUBLEBUFFER
-               private int cached_splitter_location;
-#endif
+               private Brush inactive_text_brush;
                #endregion
 
                #region Contructors
                public PropertyGridView (PropertyGrid propertyGrid) {
                        property_grid = propertyGrid;
 
-                       property_grid.SelectedGridItemChanged += new SelectedGridItemChangedEventHandler (SelectedGridItemChanged);
-                       property_grid.PropertyValueChanged += new PropertyValueChangedEventHandler (PropertyValueChanged);
-                       property_grid.SelectedObjectsChanged += new EventHandler (SelectedObjectsChanged);
-
-                       string_format = new StringFormat();
+                       string_format = new StringFormat ();
                        string_format.FormatFlags = StringFormatFlags.NoWrap;
                        string_format.Trimming = StringTrimming.None;
 
-                       grid_textbox = new PropertyGridTextBox();
-                       grid_textbox.DropDownButtonClicked +=new EventHandler(DropDownButtonClicked);
-                       grid_textbox.DialogButtonClicked +=new EventHandler(DialogButtonClicked);
+                       grid_textbox = new PropertyGridTextBox ();
+                       grid_textbox.DropDownButtonClicked +=new EventHandler (DropDownButtonClicked);
+                       grid_textbox.DialogButtonClicked +=new EventHandler (DialogButtonClicked);
 
-                       dropdown_form = new PropertyGridDropDown();
+                       dropdown_form = new PropertyGridDropDown ();
                        dropdown_form.FormBorderStyle = FormBorderStyle.None;
                        dropdown_form.StartPosition = FormStartPosition.Manual;
                        dropdown_form.ShowInTaskbar = false;
@@ -88,154 +82,108 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        dialog_form.FormBorderStyle = FormBorderStyle.None;
                        dialog_form.ShowInTaskbar = false;
 
-                       skipped_grid_items = 0;
                        row_height = Font.Height + font_height_padding;
 
                        grid_textbox.Visible = false;
                        grid_textbox.Font = this.Font;
                        grid_textbox.BackColor = SystemColors.Window;
                        // Not working at all, used to??
-                       grid_textbox.Validating += new CancelEventHandler(TextBoxValidating);
-                       grid_textbox.ToggleValue+=new EventHandler(grid_textbox_ToggleValue);
-                       this.Controls.Add(grid_textbox);
+                       // grid_textbox.Validating += new CancelEventHandler (TextBoxValidating);
+                       grid_textbox.ToggleValue+=new EventHandler (grid_textbox_ToggleValue);
+                       this.Controls.Add (grid_textbox);
 
-                       vbar = new ImplicitVScrollBar();
+                       vbar = new ImplicitVScrollBar ();
                        vbar.Visible = false;
-                       vbar.ValueChanged+=new EventHandler(HandleValueChanged);
+                       vbar.Value = 0;
+                       vbar.ValueChanged+=new EventHandler (VScrollBar_HandleValueChanged);
                        vbar.Dock = DockStyle.Right;
-                       this.Controls.AddImplicit(vbar);
+                       this.Controls.AddImplicit (vbar);
 
                        resizing_grid = false;
 
-                       bold_font = new Font(this.Font, FontStyle.Bold);
+                       bold_font = new Font (this.Font, FontStyle.Bold);
+                       inactive_text_brush = new SolidBrush (ThemeEngine.Current.ColorGrayText);
 
-                       ForeColorChanged+=new EventHandler(RedrawEvent);
-                       BackColorChanged+=new System.EventHandler(RedrawEvent);
-                       FontChanged+=new EventHandler(RedrawEvent);
+                       ForeColorChanged+=new EventHandler (RedrawEvent);
+                       BackColorChanged+=new System.EventHandler (RedrawEvent);
+                       FontChanged+=new EventHandler (RedrawEvent);
                        
-                       SetStyle(ControlStyles.Selectable, true);
-#if DOUBLEBUFFER
-                       SetStyle(ControlStyles.DoubleBuffer, true);
-#endif
-                       SetStyle(ControlStyles.UserPaint, true);
-                       SetStyle(ControlStyles.AllPaintingInWmPaint, true);
-#if DOUBLEBUFFER
-                       SetStyle(ControlStyles.ResizeRedraw, true);
-#endif
+                       SetStyle (ControlStyles.Selectable, true);
+                       SetStyle (ControlStyles.DoubleBuffer, true);
+                       SetStyle (ControlStyles.UserPaint, true);
+                       SetStyle (ControlStyles.AllPaintingInWmPaint, true);
+                       SetStyle (ControlStyles.ResizeRedraw, true);
                }
 
                #endregion
 
                #region Protected Instance Methods
 
-               protected override void OnFontChanged(EventArgs e) {
+               protected override void OnFontChanged (EventArgs e) {
                        base.OnFontChanged (e);
 
-                       bold_font = new Font(this.Font, FontStyle.Bold);
+                       bold_font = new Font (this.Font, FontStyle.Bold);
                        row_height = Font.Height + font_height_padding;
                }
 
-               void InvalidateGridItemLabel (GridItem item)
-               {
-                       Invalidate (new Rectangle (0, item.Top, SplitterLocation, row_height));
-               }
-
-#if !DOUBLEBUFFER
-               void InvalidateGridItem (GridItem item)
-               {
-                       Invalidate (new Rectangle (0, item.Top, Width, row_height));
-               }
-#endif
-
-               void CalcHeightOfGridItems (GridItemCollection col, ref int amount)
+               private void InvalidateItemLabel (GridEntry item)
                {
-                       foreach (GridItem i in col) {
-                               amount += row_height;
-                               if (i.Expanded)
-                                       CalcHeightOfGridItems (i.GridItems, ref amount);
-                       }
+                       Invalidate (new Rectangle (0, ((GridEntry)item).Top, SplitterLocation, row_height));
                }
 
-               public void RedrawBelowItemOnExpansion (GridItem item)
+               private void InvalidateItem (GridEntry item)
                {
-                       grid_textbox_Hide ();
-#if DOUBLEBUFFER
-                       Invalidate(new Rectangle (0, item.Top, Width, Height - item.Top));
-#else
-                       // ugh, we need to recurse down into all our
-                       // group items to figure out the space to
-                       // scroll..
-                       int amount = 0;
+                       if (item == null)
+                               return;
 
-                       CalcHeightOfGridItems (item.GridItems, ref amount);
+                       Rectangle rect = new Rectangle (0, item.Top, Width, row_height);
+                       Invalidate (rect);
 
                        if (item.Expanded) {
-                               XplatUI.ScrollWindow (Handle,
-                                                     new Rectangle (0, item.Top + row_height,
-                                                                    Width, Height - item.Top - row_height),
-                                                     0, amount, false);
-                       }
-                       else {
-                               XplatUI.ScrollWindow (Handle,
-                                                     new Rectangle (0, item.Top + row_height,
-                                                                    Width, Height - item.Top - row_height),
-                                                     0, -amount, false);
+                               rect = new Rectangle (0, item.Top + row_height, Width,
+                                                     Height - (item.Top + row_height));
+                               Invalidate (rect);
                        }
-                       InvalidateGridItem (item);
-                       Update();
-#endif
-                       grid_textbox_Show (property_grid.SelectedGridItem);
                }
 
-               protected override void OnDoubleClick(EventArgs e) {
-                       if (property_grid.SelectedGridItem.Expandable) {
+               protected override void OnDoubleClick (EventArgs e) 
+               {
+                       if (property_grid.SelectedGridItem != null && property_grid.SelectedGridItem.Expandable)
                                property_grid.SelectedGridItem.Expanded = !property_grid.SelectedGridItem.Expanded;
-                       }
-                       else {
-                               GridItem item = property_grid.SelectedGridItem;
-                               if (item.GridItemType == GridItemType.Property
-                                   && !item.PropertyDescriptor.IsReadOnly) {
-                                       ToggleValue();
-                                       Invalidate();
-                               }
-                       }
+                       else
+                               ToggleValue ((GridEntry)property_grid.SelectedGridItem);
                }
 
-               protected override void OnPaint(PaintEventArgs e) {
-                       // Decide if we need a scrollbar
-                       open_grid_item_count = 0;
-
+               protected override void OnPaint (PaintEventArgs e) 
+               {
                        // Background
                        e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
                        
                        int yLoc = -vbar.Value*row_height;
+                       if (property_grid.RootGridItem != null)
+                               DrawGridItems (property_grid.RootGridItem.GridItems, e, 1, ref yLoc);
 
-                       if (property_grid.root_grid_item != null)
-                               DrawGridItems(property_grid.root_grid_item.GridItems, e, 1, ref yLoc);
-
-                       UpdateScrollBar();
+                       UpdateScrollBar ();
                }
 
-               protected override void OnMouseWheel(MouseEventArgs e) {
-                       if (vbar == null || !vbar.Visible) {
+               protected override void OnMouseWheel (MouseEventArgs e) 
+               {
+                       if (vbar == null || !vbar.Visible)
                                return;
-                       }
-
-                       if (e.Delta < 0) {
-                               vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum);
-                       } else {
-                               vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
-                       }
+                       if (e.Delta < 0)
+                               vbar.Value = Math.Min (vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - vbar.SmallChange);
+                       else
+                               vbar.Value = Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines);
                        base.OnMouseWheel (e);
                }
 
 
                protected override void OnMouseMove (MouseEventArgs e) {
-                       if (property_grid.root_grid_item == null)
+                       if (property_grid.RootGridItem == null)
                                return;
 
                        if (resizing_grid) {
-                               int loc = Math.Max(e.X,2*V_INDENT);
+                               int loc = Math.Max (e.X,2*V_INDENT);
                                SplitterPercent = 1.0*loc/Width;
                        }
                        if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) 
@@ -245,29 +193,34 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        base.OnMouseMove (e);
                }
 
-               protected override void OnMouseDown (MouseEventArgs e) {
-                       if (property_grid.root_grid_item == null)
+               protected override void OnMouseDown (MouseEventArgs e) 
+               {
+                       base.OnMouseDown (e);
+                       if (property_grid.RootGridItem == null)
+                               return;
+
+                       if (!TrySetEntry ((GridEntry)property_grid.SelectedGridItem, grid_textbox.Text)) {
+                               FocusSelection ();
                                return;
+                       }
 
                        if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) {
                                resizing_grid = true;
                        }
                        else {
                                int offset = -vbar.Value*row_height;
-                               GridItem foundItem = GetSelectedGridItem(property_grid.root_grid_item.GridItems, e.Y, ref offset);
-                               
+                               GridItem foundItem = GetSelectedGridItem (property_grid.RootGridItem.GridItems, e.Y, ref offset);
+
                                if (foundItem != null) {
-                                       if (foundItem.Expandable) {
-                                               if (e.X >=3 && e.X <= 11 && (e.Y % row_height >= row_height/2-2 && e.Y % row_height <= row_height/2+4)) {
-                                                       foundItem.Expanded = !foundItem.Expanded;
-                                               }
-                                       }
-                                       this.property_grid.SelectedGridItem = foundItem;
+                                       if (foundItem.Expandable && ((GridEntry)foundItem).PlusMinusBounds.Contains (e.X, e.Y))
+                                               foundItem.Expanded = !foundItem.Expanded;
                                        
-                                       grid_textbox.SendMouseDown (grid_textbox.PointToClient (PointToScreen (e.Location)));
+                                       this.property_grid.SelectedGridItem = foundItem;
+                                       if (!GridLabelHitTest (e.X)) {
+                                               // send mouse down so we get the carret under cursor
+                                               grid_textbox.SendMouseDown (PointToScreen (e.Location));
+                                       }
                                }
-                               
-                               base.OnMouseDown (e);
                        }
                }
 
@@ -276,34 +229,15 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        base.OnMouseUp (e);
                }
 
-               protected override void OnResize(EventArgs e) {
-                       SuspendLayout ();
-                       grid_textbox.Hide ();
-                       ResumeLayout (false);
-
-#if !DOUBLEBUFFER
-                       // we need to explicitly handle this redraw
-                       // before getting to the scrollwindow, or we
-                       // end up having to redraw the entire item
-                       // value area because the exposed areas are
-                       // unioned.
-                       Update ();
-#endif
-
+               protected override void OnResize (EventArgs e) {
                        base.OnResize (e);
-#if !DOUBLEBUFFER
-                       if (cached_splitter_location != SplitterLocation) {
-                               int x = cached_splitter_location > SplitterLocation ? SplitterLocation : cached_splitter_location;
-                               XplatUI.ScrollWindow (Handle,
-                                                     new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height),
-                                                     SplitterLocation - cached_splitter_location, 0, false);
-                               Update();
+                       if (property_grid.SelectedGridItem != null) { // initialized already
+                               UpdateView ();
+                               // MS scrolls to the currently selected item on resize, even
+                               // when it's not in the visible area.
+                               // 
+                               ScrollToItem ((GridEntry)property_grid.SelectedGridItem);
                        }
-                       cached_splitter_location = SplitterLocation;
-#endif
-                       SuspendLayout ();
-                       grid_textbox_Show (property_grid.SelectedGridItem);
-                       ResumeLayout (false);
                }
 
                private void UnfocusSelection ()
@@ -311,20 +245,28 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        Select (this);
                }
 
+               private void FocusSelection ()
+               {
+                       Select (grid_textbox);
+               }
+
                protected override bool ProcessDialogKey (Keys keyData) {
-                       GridItem selectedItem = property_grid.SelectedGridItem;
+                       GridEntry selectedItem = (GridEntry) property_grid.SelectedGridItem;
                        if (selectedItem != null
-                           && grid_textbox.Visible
-                           /* if the textbox has focus? */) {
+                           && grid_textbox.Visible) {
                                switch (keyData) {
                                case Keys.Enter:
-                                       SetPropertyValue(selectedItem.PropertyDescriptor.Converter.ConvertFromString(grid_textbox.Text));
-                                       UnfocusSelection ();
+                                       if (TrySetEntry (selectedItem, grid_textbox.Text))
+                                               UnfocusSelection ();
                                        return true;
                                case Keys.Escape:
-                                       grid_textbox.Text = selectedItem.PropertyDescriptor.Converter.ConvertToString(selectedItem.Value);
+                                       if (selectedItem.IsEditable)
+                                               UpdateItem (selectedItem); // reset value
                                        UnfocusSelection ();
                                        return true;
+                               case Keys.Tab:
+                                       FocusSelection ();
+                                       return true;
                                default:
                                        return false;
                                }
@@ -332,6 +274,25 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        return base.ProcessDialogKey (keyData);
                }
 
+               private bool TrySetEntry (GridEntry entry, object value)
+               {
+                       if (entry == null || grid_textbox.Text.Equals (entry.ValueText))
+                               return true;
+
+                       if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) ||
+                           !entry.IsMerged || entry.HasMergedValue || 
+                           (!entry.HasMergedValue && grid_textbox.Text != String.Empty)) {
+                               string error = null;
+                               bool changed = entry.SetValue (value, out error);
+                               if (!changed && error != null) {
+                                       if (property_grid.ShowError (error, MessageBoxButtons.OKCancel) == DialogResult.Cancel)
+                                               UpdateItem (entry); // restore value, repaint, etc
+                                       else
+                                               return false;
+                               }
+                       }
+                       return true;
+               }
 
                protected override bool IsInputKey (Keys keyData) {
                        switch (keyData) {
@@ -359,7 +320,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        /* move back up the visible rows (and up the hierarchy as necessary) until
                           up_count == 0, or we reach the top of the display */
                        while (up_count > 0) {
-                               items = item.Parent != null ? item.Parent.GridItems : property_grid.root_grid_item.GridItems;
+                               items = item.Parent != null ? item.Parent.GridItems : property_grid.RootGridItem.GridItems;
                                index = items.IndexOf (item);
 
                                if (index == 0) {
@@ -420,7 +381,8 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        return item;
                }
 
-               protected override void OnKeyDown(KeyEventArgs e) {
+               protected override void OnKeyDown (KeyEventArgs e) 
+               {
                        GridEntry selectedItem = (GridEntry)property_grid.SelectedGridItem;
 
                        if (selectedItem == null) {
@@ -429,6 +391,11 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                return;
                        }
 
+                       if (!TrySetEntry (selectedItem, grid_textbox.Text)) {
+                               FocusSelection ();
+                               return;
+                       }
+
                        switch (e.KeyData & Keys.KeyCode) {
                        case Keys.Left:
                                if (e.Control) {
@@ -493,14 +460,14 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                break;
                        case Keys.End:
                                /* find the last, most deeply nested visible item */
-                               GridEntry item = (GridEntry)property_grid.root_grid_item.GridItems[property_grid.root_grid_item.GridItems.Count - 1];
+                               GridEntry item = (GridEntry)property_grid.RootGridItem.GridItems[property_grid.RootGridItem.GridItems.Count - 1];
                                while (item.Expandable && item.Expanded)
                                        item = (GridEntry)item.GridItems[item.GridItems.Count - 1];
                                property_grid.SelectedGridItem = item;
                                e.Handled = true;
                                break;
                        case Keys.Home:
-                               property_grid.SelectedGridItem = property_grid.root_grid_item.GridItems[0];
+                               property_grid.SelectedGridItem = property_grid.RootGridItem.GridItems[0];
                                e.Handled = true;
                                break;
                        }
@@ -512,41 +479,36 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                #region Private Helper Methods
 
-               private int SplitterLocation{
+               private int SplitterLocation {
                        get {
                                return (int)(splitter_percent*Width);
                        }
                }
 
-               private double SplitterPercent{
+               private double SplitterPercent {
                        set {
                                int old_splitter_location = SplitterLocation;
                                
-                               splitter_percent = Math.Max(Math.Min(value, .9),.1);
+                               splitter_percent = Math.Max (Math.Min (value, .9),.1);
 
                                if (old_splitter_location != SplitterLocation) {
-                                       grid_textbox_Hide ();
                                        int x = old_splitter_location > SplitterLocation ? SplitterLocation : old_splitter_location;
-#if DOUBLEBUFFER
-                                       Invalidate(new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height));
-#else
-                                       XplatUI.ScrollWindow (Handle,
-                                                             new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height),
-                                                             SplitterLocation - old_splitter_location, 0, false);
-                                       Update ();
-#endif
-                                       grid_textbox_Show (property_grid.SelectedGridItem);
+                                       Invalidate (new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height));
+                                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
                                }
-
-#if !DOUBLEBUFFER
-                               cached_splitter_location = SplitterLocation;
-#endif
                        }
                        get {
                                return splitter_percent;
                        }
                }
 
+               private bool GridLabelHitTest (int x)
+               {
+                       if (0 <= x && x <= splitter_percent * this.Width)
+                               return true;
+                       return false;
+               }
+
                private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y, ref int current) {
                        foreach (GridItem child_grid_item in grid_items) {
                                if (y > current && y < current + row_height) {
@@ -554,7 +516,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                }
                                current += row_height;
                                if (child_grid_item.Expanded) {
-                                       GridItem foundItem = GetSelectedGridItem(child_grid_item.GridItems, y, ref current);
+                                       GridItem foundItem = GetSelectedGridItem (child_grid_item.GridItems, y, ref current);
                                        if (foundItem != null)
                                                return foundItem;
                                }
@@ -562,43 +524,78 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        return null;
                }
 
-               private void UpdateScrollBar() {
-                       int visible_rows = this.ClientRectangle.Height/row_height;
-                       if (open_grid_item_count > visible_rows) {
+               private int GetVisibleItemsCount (GridEntry entry)
+               {
+                       if (entry == null)
+                               return 0;
+
+                       int count = 0;
+                       foreach (GridEntry e in entry.GridItems) {
+                               count += 1;
+                               if (e.Expandable && e.Expanded)
+                                       count += GetVisibleItemsCount (e);
+                       }
+                       return count;
+               }
+
+               private int GetVisibleRowsCount ()
+               {
+                       return this.Height / row_height;
+               }
+
+               private void UpdateScrollBar ()
+               {
+                       if (property_grid.RootGridItem == null)
+                               return;
+
+                       int visibleRows = GetVisibleRowsCount ();
+                       int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
+                       if (openedItems > visibleRows) {
                                vbar.Visible = true;
                                vbar.SmallChange = 1;
                                vbar.Minimum = 0;
-                               vbar.Maximum = open_grid_item_count-1;
-                               vbar.LargeChange = visible_rows;
-                       }
-                       else {
+                               vbar.Maximum = openedItems - 1;
+                               vbar.LargeChange = visibleRows;
+                       } else {
+                               vbar.Value = 0;
                                vbar.Visible = false;
                        }
-
+                       UpdateGridTextBoxBounds ((GridEntry)property_grid.SelectedGridItem);
                }
 
+               // private bool GetScrollBarVisible ()
+               // {
+               //      if (property_grid.RootGridItem == null)
+               //              return false;
+                // 
+               //      int visibleRows = GetVisibleRowsCount ();
+               //      int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
+               //      if (openedItems > visibleRows)
+               //              return true;
+               //      return false;
+               // }
                #region Drawing Code
 
-               private void DrawGridItems(GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
+               private void DrawGridItems (GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
                        foreach (GridItem grid_item in grid_items) {
-                               DrawGridItem (grid_item, pevent, depth, ref yLoc);
+                               DrawGridItem ((GridEntry)grid_item, pevent, depth, ref yLoc);
                                if (grid_item.Expanded)
-                                       DrawGridItems(grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
+                                       DrawGridItems (grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
                        }
                }
 
-               private void DrawGridItemLabel(GridItem grid_item, PaintEventArgs pevent, int depth, Rectangle rect) {
+               private void DrawGridItemLabel (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) {
                        Font font = this.Font;
                        Brush brush;
 
                        if (grid_item.GridItemType == GridItemType.Category) {
                                font = bold_font;
-                               brush = SystemBrushes.ControlDark;
+                               brush = SystemBrushes.ControlText;
 
-                               pevent.Graphics.DrawString (grid_item.Label, font, brush, rect.X + 1, rect.Y + 2);
+                               pevent.Graphics.DrawString (grid_item.Label, font, brush, rect.X + 1, rect.Y + ENTRY_SPACING);
                                if (grid_item == property_grid.SelectedGridItem) {
                                        SizeF size = pevent.Graphics.MeasureString (grid_item.Label, font);
-                                       ControlPaint.DrawFocusRectangle (pevent.Graphics, new Rectangle(rect.X + 1, rect.Y+2, (int)size.Width, (int)size.Height));
+                                       ControlPaint.DrawFocusRectangle (pevent.Graphics, new Rectangle (rect.X + 1, rect.Y+ENTRY_SPACING, (int)size.Width, (int)size.Height));
                                }
                        }
                        else {
@@ -613,106 +610,83 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                        brush = SystemBrushes.HighlightText;
                                }
                                else {
-                                       brush = SystemBrushes.WindowText;
-                                       if (grid_item.PropertyDescriptor.IsReadOnly
-                                           && !grid_item.Expandable)
-                                               brush = SystemBrushes.InactiveCaption;
+                                       brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
                                }
                        }
-
                        pevent.Graphics.DrawString (grid_item.Label, font, brush,
-                                                   new Rectangle (rect.X + 1, rect.Y + 2, rect.Width - 2, rect.Height - 2),
+                                                   new Rectangle (rect.X + 1, rect.Y + ENTRY_SPACING, rect.Width - ENTRY_SPACING, rect.Height - ENTRY_SPACING),
                                                    string_format);
                }
 
-               private void DrawGridItemValue(GridItem grid_item, PaintEventArgs pevent, int depth, Rectangle rect) {
-                       // Value
-                       if (grid_item.PropertyDescriptor != null) {
-
-                               bool paintsValue = false;
-                               UITypeEditor editor = (UITypeEditor)grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
-                               if (editor != null) {
-                                       paintsValue = editor.GetPaintValueSupported();
-                               }
-
-                               int xLoc = SplitterLocation+1;
-                               if (paintsValue) {
-                                       pevent.Graphics.DrawRectangle(Pens.Black, SplitterLocation+2,rect.Y+2, 20, row_height-4);
-                                       try {
-                                               editor.PaintValue(grid_item.Value, pevent.Graphics, new Rectangle(SplitterLocation+3,rect.Y+3, 19, row_height-5));
-                                       }
-                                       catch (Exception) {
-                                       }
-                                       xLoc += 27;
-                               }
-
-                               try {
-                                       if (grid_item.PropertyDescriptor.Converter != null) {
-                                               Font font = this.Font;
-                                               Brush brush;
-
-                                               string value = grid_item.PropertyDescriptor.Converter.ConvertToString(grid_item.Value);
-                                               if (((GridEntry)grid_item).CanResetValue ())
-                                                       font = bold_font;
-
-                                               brush = SystemBrushes.WindowText;
-                                               if (grid_item.PropertyDescriptor.IsReadOnly
-                                                   && !grid_item.Expandable)
-                                                       brush = SystemBrushes.InactiveCaption;
-
-                                               pevent.Graphics.DrawString(value, font,
-                                                                          brush,
-                                                                          new RectangleF(xLoc, rect.Y+2,
-                                                                                         ClientRectangle.Width-(xLoc), row_height),string_format);
-                                       }
-                                       else {
-                                               Console.WriteLine("No converter for type {0}",grid_item.PropertyDescriptor.PropertyType);
-                                       }
-
-                               }
-                               catch (Exception) {
-                               }
+               private void DrawGridItemValue (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) 
+               {
+                       if (grid_item.PropertyDescriptor == null)
+                               return; 
+
+                       int xLoc = SplitterLocation+ENTRY_SPACING;
+                       if (grid_item.PaintValueSupported) {
+                               pevent.Graphics.DrawRectangle (Pens.Black, SplitterLocation + ENTRY_SPACING, 
+                                                              rect.Y + 2, VALUE_PAINT_WIDTH + 1, row_height - ENTRY_SPACING*2);
+                               grid_item.PaintValue (pevent.Graphics, 
+                                                     new Rectangle (SplitterLocation + ENTRY_SPACING + 1, 
+                                                                    rect.Y + ENTRY_SPACING + 1,
+                                                                    VALUE_PAINT_WIDTH, row_height - (ENTRY_SPACING*2 +1)));
+                               xLoc += VALUE_PAINT_INDENT;
                        }
+
+                       Font font = this.Font;
+                       if (grid_item.IsResetable || !grid_item.HasDefaultValue)
+                               font = bold_font;
+                       Brush brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
+                       string valueText = grid_item.IsMerged && !grid_item.HasMergedValue ? String.Empty : grid_item.ValueText;
+                       pevent.Graphics.DrawString (valueText, font,
+                                                   brush,
+                                                   new RectangleF (xLoc + ENTRY_SPACING, rect.Y + ENTRY_SPACING,
+                                                                   ClientRectangle.Width-(xLoc), row_height - ENTRY_SPACING*2), 
+                                                   string_format);
                }
 
-               private void DrawGridItem (GridItem grid_item, PaintEventArgs pevent, int depth, ref int yLoc) {
+               private void DrawGridItem (GridEntry grid_item, PaintEventArgs pevent, int depth, ref int yLoc) {
                        if (yLoc > -row_height && yLoc < ClientRectangle.Height) {
-
                                // Left column
                                pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor),
                                                               0, yLoc, V_INDENT, row_height);
                        
-                               if (grid_item.Expandable) {
-                                       grid_item.PlusMinusBounds = DrawPlusMinus(pevent.Graphics, 3, yLoc+row_height/2-3, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
-                               }
-                       
                                if (grid_item.GridItemType == GridItemType.Category) {
                                        pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.CategoryForeColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), row_height);
                                }
 
-                               DrawGridItemLabel(grid_item, pevent,
-                                                 depth,
-                                                 new Rectangle(depth * V_INDENT, yLoc, SplitterLocation - depth * V_INDENT, row_height));
-                               DrawGridItemValue(grid_item, pevent,
+                               DrawGridItemLabel (grid_item, pevent,
+                                                  depth,
+                                                 new Rectangle (depth * V_INDENT, yLoc, SplitterLocation - depth * V_INDENT, row_height));
+                               DrawGridItemValue (grid_item, pevent,
                                                  depth,
-                                                 new Rectangle(SplitterLocation + 2 , yLoc, ClientRectangle.Width - SplitterLocation - 2 - (vbar.Visible ? vbar.Width : 0), row_height));
+                                                 new Rectangle (SplitterLocation + ENTRY_SPACING , yLoc, 
+                                                                ClientRectangle.Width - SplitterLocation - ENTRY_SPACING - (vbar.Visible ? vbar.Width : 0), 
+                                                                row_height));
 
                                if (grid_item.GridItemType != GridItemType.Category) {
-                                       Pen pen = ThemeEngine.Current.ResPool.GetPen(property_grid.LineColor);
+                                       Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.LineColor);
                                        // vertical divider line
-                                       pevent.Graphics.DrawLine(pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height);
+                                       pevent.Graphics.DrawLine (pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height);
                        
                                        // draw the horizontal line
-                                       pevent.Graphics.DrawLine(pen, 0, yLoc + row_height, ClientRectangle.Width, yLoc + row_height);
+                                       pevent.Graphics.DrawLine (pen, 0, yLoc + row_height, ClientRectangle.Width, yLoc + row_height);
+                               }                               
+                               
+                               if (grid_item.Expandable) {
+                                       int y = yLoc + row_height / 2 - ENTRY_SPACING + 1;
+                                       grid_item.PlusMinusBounds = DrawPlusMinus (pevent.Graphics, (depth - 1) * V_INDENT + ENTRY_SPACING + 1, 
+                                                                                  y, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
                                }
+
                        }
                        grid_item.Top = yLoc;
                        yLoc += row_height;
-                       open_grid_item_count++;
                }
 
                private Rectangle DrawPlusMinus (Graphics g, int x, int y, bool expanded, bool category) {
-                       Rectangle bounds = new Rectangle(x, y, 8, 8);
+                       Rectangle bounds = new Rectangle (x, y, 8, 8);
                        if (!category) g.FillRectangle (Brushes.White, bounds);
                        Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.ViewForeColor);
                        g.DrawRectangle (pen, bounds);
@@ -726,59 +700,25 @@ namespace System.Windows.Forms.PropertyGridInternal {
                #endregion
 
                #region Event Handling
-               private void RedrawEvent (object sender, System.EventArgs e) {
-                       Refresh();
+               private void RedrawEvent (object sender, System.EventArgs e) 
+               {
+                       Refresh ();
                }
 
-               private void TextBoxValidating (object sender, CancelEventArgs e) {
-                       if (this.property_grid.SelectedGridItem != null) {
-                               PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                               if (desc != null) {
-                                       try {
-                                               if (desc.Converter != null) {
-                                                       SetPropertyValue(desc.Converter.ConvertFromString(grid_textbox.Text));
-                                               }
-                                               else {
-                                                       Console.WriteLine("No converter for type {0}",desc.PropertyType);
-                                               }
-                                       }
-                                       catch (Exception ex) {
-                                               Console.WriteLine("Error converting string: " + ex.Message);
-                                       }
-                               }
-                       }
-               }
+               // private void TextBoxValidating (object sender, CancelEventArgs e)
+               // {
+               //      GridEntry entry = (GridEntry) property_grid.SelectedGridItem;
+               //      if (entry != null && entry.IsEditable)
+               //              TrySetEntry (entry, grid_textbox.Text);
+               // }
 
                #endregion
 
-               private void ToggleValue() {
-                       if (property_grid.SelectedGridItem.GridItemType == GridItemType.Property) {
-                               if (property_grid.SelectedGridItem.PropertyDescriptor != null) {
-                                       if (property_grid.SelectedGridItem.PropertyDescriptor.PropertyType == typeof(bool))
-                                               SetPropertyValue(!(bool)property_grid.SelectedGridItem.Value);
-                                       else if (property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValuesSupported()){
-                                               System.ComponentModel.TypeConverter.StandardValuesCollection coll = 
-                                                       (System.ComponentModel.TypeConverter.StandardValuesCollection)property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValues();
-                                               for (int i = 0; i < coll.Count; i++) {
-                                                       if (property_grid.SelectedGridItem.Value.Equals(coll[i])){
-                                                               if (i < coll.Count-1)
-                                                                       SetPropertyValue(coll[i+1]);
-                                                               else
-                                                                       SetPropertyValue(coll[0]);
-                                                               break;
-                                                       }
-
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               private void listBox_MouseUp(object sender, MouseEventArgs e) {
+               private void listBox_MouseUp (object sender, MouseEventArgs e) {
                        AcceptListBoxSelection (sender);
                }
 
-               private void listBox_KeyDown(object sender, KeyEventArgs e)
+               private void listBox_KeyDown (object sender, KeyEventArgs e)
                {
                        switch (e.KeyData & Keys.KeyCode) {
                        case Keys.Enter:
@@ -790,260 +730,190 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        }
                }
 
-               void AcceptListBoxSelection (object sender) {
-                       if (this.property_grid.SelectedGridItem != null) {
-                               PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                               if (desc != null) {
-                                       SetPropertyValue(((ListBox)sender).SelectedItem);
-                               }
+               void AcceptListBoxSelection (object sender) 
+               {
+                       GridEntry entry = this.property_grid.SelectedGridItem as GridEntry;
+                       if (entry != null) {
+                               grid_textbox.Text = (string) ((ListBox) sender).SelectedItem;
+                               if (TrySetEntry (entry, (string) ((ListBox) sender).SelectedItem))
+                                       UnfocusSelection ();
                        }
                        CloseDropDown ();
                }
 
-               private void SetPropertyValue(object newVal) {
-                       if (property_grid.SelectedGridItem == null)
-                               return;
-
-                       PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                       if (desc == null)
+               private void DropDownButtonClicked (object sender, EventArgs e) 
+               {
+                       GridEntry entry = property_grid.SelectedGridItem as GridEntry;
+                       if (entry == null)
                                return;
 
-                       for (int i = 0; i < ((GridEntry)property_grid.SelectedGridItem).SelectedObjects.Length; i ++) {
-                               object target = property_grid.GetTarget (property_grid.SelectedGridItem, i);
-                               desc.SetValue(target, newVal);
-                       }
-
-                       property_grid.PropertyValueChangedInternal ();
-               }
-
-               private void DropDownButtonClicked (object sender, EventArgs e) {
-                       UITypeEditor editor = property_grid.SelectedGridItem.PropertyDescriptor.GetEditor (typeof (UITypeEditor)) as UITypeEditor;
-                       if (editor == null) {
+                       if (entry.HasCustomEditor) {
+                               entry.EditValue ((IWindowsFormsEditorService) this);
+                       } else {
                                if (dropdown_form.Visible) {
                                        CloseDropDown ();
                                }
                                else {
-                                       TypeConverter converter = property_grid.SelectedGridItem.PropertyDescriptor.Converter;
-                                       ICollection std_values;
-
-                                       if (!converter.GetStandardValuesSupported ())
-                                               return;
-
-                                       std_values = converter.GetStandardValues();
-                                       if (std_values == null)
-                                               return;
-
-                                       ListBox listBox = new ListBox();
-                                       listBox.BorderStyle = BorderStyle.FixedSingle;
-                                       int selected_index = 0;
-                                       int i = 0;
-                                       object selected_value = property_grid.SelectedGridItem.Value;
-                                       foreach (object obj in std_values) {
-                                               listBox.Items.Add(obj);
-                                               if (selected_value != null && selected_value.Equals(obj))
-                                                       selected_index = i;
-                                               i++;
+                                       ICollection std_values = entry.AcceptedValues;
+                                       if (std_values != null) {
+                                               ListBox listBox = new ListBox ();
+                                               listBox.BorderStyle = BorderStyle.FixedSingle;
+                                               int selected_index = 0;
+                                               int i = 0;
+                                               foreach (object obj in std_values) {
+                                                       listBox.Items.Add (obj);
+                                                       if (entry.ValueText != null && entry.ValueText.Equals (obj))
+                                                               selected_index = i;
+                                                       i++;
+                                               }
+                                               listBox.Height = row_height * Math.Min (listBox.Items.Count, 15);
+                                               listBox.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0);
+                                               listBox.KeyDown += new KeyEventHandler (listBox_KeyDown);
+                                               listBox.MouseUp+=new MouseEventHandler (listBox_MouseUp);
+                                               if (std_values.Count > 0)
+                                                       listBox.SelectedIndex = selected_index;
+                                               DropDownControl (listBox);
                                        }
-                                       listBox.Height = row_height * Math.Min (listBox.Items.Count, 15);
-                                       listBox.SelectedIndex = selected_index;
-                                       listBox.KeyDown += new KeyEventHandler(listBox_KeyDown);
-                                       listBox.MouseUp+=new MouseEventHandler(listBox_MouseUp);
-
-                                       DropDownControl (listBox);
                                }
-                       } else { // use editor
-                               SetPropertyValueFromUITypeEditor (editor);
                        }
                }
 
-               void SetPropertyValueFromUITypeEditor (UITypeEditor editor)
+               private void DialogButtonClicked (object sender, EventArgs e) 
                {
-                       ServiceContainer service_container = new ServiceContainer ();
-                       service_container.AddService (typeof (IWindowsFormsEditorService), this);
-                       object initial_value = property_grid.SelectedGridItem.Value;
-                       object value = editor.EditValue (
-                               (ITypeDescriptorContext)property_grid.SelectedGridItem,
-                               service_container,
-                               initial_value);
-
-                       SetPropertyValue (value);
-               }
-               
-               private void DialogButtonClicked(object sender, EventArgs e) {
-                       UITypeEditor editor = property_grid.SelectedGridItem.PropertyDescriptor.GetEditor (typeof (UITypeEditor)) as UITypeEditor;
-                       if (editor != null)
-                               SetPropertyValueFromUITypeEditor (editor);
+                       GridEntry entry = property_grid.SelectedGridItem as GridEntry;
+                       if (entry != null && entry.HasCustomEditor)
+                               entry.EditValue ((IWindowsFormsEditorService) this);
                }
 
-               private void HandleValueChanged(object sender, EventArgs e) {
-                       if (vbar.Value <= 0) {
-                               vbar.Value = 0;
-                       }
-                       if (vbar.Value > vbar.Maximum-ClientRectangle.Height/row_height) {
-                               vbar.Value = vbar.Maximum-ClientRectangle.Height/row_height+1;
-                       }
-
-                       int scroll_amount = (skipped_grid_items-vbar.Value)*row_height;
-
-                       if (scroll_amount == 0)
-                               return;
-
-                       grid_textbox_Hide ();
-
-                       skipped_grid_items = vbar.Value;
-                       XplatUI.ScrollWindow(Handle, 0, scroll_amount, false);
-#if DOUBLEBUFFER
-                       Invalidate ();
-#endif
-                       Update ();
+               private void VScrollBar_HandleValueChanged (object sender, EventArgs e) 
+               {
+                       UpdateView ();
+               }
 
-                       if (property_grid.SelectedGridItem != null)
-                               grid_textbox_Show (property_grid.SelectedGridItem);
+               private void grid_textbox_ToggleValue (object sender, EventArgs args) 
+               {
+                       ToggleValue ((GridEntry)property_grid.SelectedGridItem);
                }
 
-               private void grid_textbox_ToggleValue(object sender, EventArgs e) {
-                       if (!property_grid.SelectedGridItem.PropertyDescriptor.IsReadOnly) {
-                               ToggleValue();
-                               Invalidate();
-                       }
+               private void ToggleValue (GridEntry entry)
+               {
+                       if (entry != null && !entry.IsReadOnly && entry.GridItemType == GridItemType.Property)
+                               entry.ToggleValue ();
                }
 
-               internal void grid_textbox_Show (GridItem forItem)
+               internal void UpdateItem (GridEntry entry)
                {
-                       if (forItem == null || forItem.PropertyDescriptor == null)
+                       if (entry == null || entry.GridItemType == GridItemType.Category || 
+                           entry.GridItemType == GridItemType.Root) {
+                               grid_textbox.Visible = false;
+                               InvalidateItem (entry);
                                return;
-
-                       SuspendLayout ();
-
-                       if (((GridEntry)forItem).CanResetValue ())
-                               grid_textbox.Font = bold_font;
-                       else
-                               grid_textbox.Font = this.Font;
-
-                       grid_textbox.ReadOnly = false;
-                       grid_textbox.DropDownButtonVisible = false;
-                       grid_textbox.DialogButtonVisible = false;
-
-                       bool paintsValue = false;
-                       UITypeEditor editor = (UITypeEditor)forItem.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
-                       if (editor != null) {
-                               paintsValue = editor.GetPaintValueSupported();
                        }
 
-                       if (editor != null) {
-                               UITypeEditorEditStyle style = editor.GetEditStyle();
-                                       
-                               switch (style) {
-                               case UITypeEditorEditStyle.DropDown:
-                                       grid_textbox.DropDownButtonVisible = true;
-                                       break;
-                               case UITypeEditorEditStyle.Modal:
-                                       grid_textbox.DialogButtonVisible = true;
-                                       break;
-                               }
-                       }
-                       else {
-                               try {
-                                       if (forItem.PropertyDescriptor.Converter != null) {
-                                               if (forItem.PropertyDescriptor.Converter.GetStandardValuesSupported()) {
-                                                       
-                                                       grid_textbox.DropDownButtonVisible = true;
-                                                       grid_textbox.ReadOnly = true;
-                                               }
-                                       }
-                                       else {
-                                               Console.WriteLine("Converter not available for type {0}",forItem.PropertyDescriptor.PropertyType);
-                                       }
-                                               
-                               }
-                               catch (Exception) {
+                       if (property_grid.SelectedGridItem == entry) {
+                               SuspendLayout ();
+                               grid_textbox.Visible = false;
+                               if (entry.IsResetable || !entry.HasDefaultValue)
+                                       grid_textbox.Font = bold_font;
+                               else
+                                       grid_textbox.Font = this.Font;
+
+                               if (entry.IsReadOnly) {
+                                       grid_textbox.DropDownButtonVisible = false;
+                                       grid_textbox.DialogButtonVisible = false;
+                                       grid_textbox.ReadOnly = true;
+                                       grid_textbox.ForeColor = SystemColors.GrayText;
+                               } else {
+                                       grid_textbox.DropDownButtonVisible = entry.AcceptedValues != null || 
+                                               entry.EditorStyle == UITypeEditorEditStyle.DropDown;
+                                       grid_textbox.DialogButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.Modal;
+                                       grid_textbox.ForeColor = SystemColors.ControlText;
+                                       grid_textbox.ReadOnly = !entry.IsEditable;
                                }
+                               UpdateGridTextBoxBounds (entry);
+                               grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText;
+                               grid_textbox.Visible = true;
+                               InvalidateItem (entry);
+                               ResumeLayout (false);
+                       } else {
+                               grid_textbox.Visible = false;
                        }
-                               
-                       grid_textbox.ReadOnly = grid_textbox.ReadOnly || forItem.PropertyDescriptor.IsReadOnly;
-                       grid_textbox.ForeColor = grid_textbox.ReadOnly ? SystemColors.InactiveCaption : SystemColors.WindowText;
-
-                       int xloc = SplitterLocation + 1 + (paintsValue ? 27 : 0);
-                       grid_textbox.SetBounds (xloc,
-                                               forItem.Top + 2,
-                                               ClientRectangle.Width - xloc - (vbar.Visible ? vbar.Width : 0),
-                                               row_height - 2);
-                       grid_textbox.Visible = true;
-
-                       ResumeLayout (false);
                }
 
-               private void grid_textbox_Hide ()
+               private void UpdateGridTextBoxBounds (GridEntry entry)
                {
-                       SuspendLayout ();
-                       grid_textbox.Bounds = Rectangle.Empty;
-                       grid_textbox.Visible = false;
-                       ResumeLayout (false);
+                       int y = -vbar.Value*row_height;
+                       CalculateItemY (entry, property_grid.RootGridItem.GridItems, ref y);
+                       int x = SplitterLocation + ENTRY_SPACING + (entry.PaintValueSupported ? VALUE_PAINT_INDENT : 0);
+                       grid_textbox.SetBounds (x + ENTRY_SPACING, y + ENTRY_SPACING,
+                                               ClientRectangle.Width - ENTRY_SPACING - x - (vbar.Visible ? vbar.Width : 0),
+                                               row_height - ENTRY_SPACING);
                }
 
-               void EnsureItemIsVisible (GridItem item)
+               // Calculates the sum of the heights of all items before the one
+               //
+               private bool CalculateItemY (GridEntry entry, GridItemCollection items, ref int y)
                {
-                       if (item.Top < 0) {
-                               // the new item is above the viewable area
-                               vbar.Value += item.Top / row_height;
-                       }
-                       else if (item.Top + row_height > Height) {
-                               // the new item is below the viewable area
-                               vbar.Value += ((item.Top + row_height) - Height) / row_height + 1;
-                       }
-                       else {
-                               // do nothing
+                       foreach (GridItem item in items) {
+                               if (item == entry)
+                                       return true;
+                               y += row_height;
+                               if (item.Expandable && item.Expanded)
+                                       if (CalculateItemY (entry, item.GridItems, ref y))
+                                               return true;
                        }
+                       return false;
                }
 
-
-               private void SelectedObjectsChanged (object sender, EventArgs args) {
-                       grid_textbox_Hide ();
-                       SelectedGridItemChanged (sender, new SelectedGridItemChangedEventArgs (property_grid.SelectedGridItem, property_grid.SelectedGridItem));
-               }
-
-               private void SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e) {
-                       if (e.OldSelection != null)
-                               InvalidateGridItemLabel (e.OldSelection);
-                               
-                       if (e.NewSelection == null)
+               private void ScrollToItem (GridEntry item)
+               {
+                       if (item == null)
                                return;
-                       
-                       InvalidateGridItemLabel (e.NewSelection);
 
-                       EnsureItemIsVisible (e.NewSelection);
+                       int itemY = -vbar.Value*row_height;
+                       int value = vbar.Value;;
+                       CalculateItemY (item, property_grid.RootGridItem.GridItems, ref itemY);
+                       if (itemY < 0) // the new item is above the viewable area
+                               value += itemY / row_height;
+                       else if (itemY + row_height > Height) // the new item is below the viewable area
+                               value += ((itemY + row_height) - Height) / row_height + 1;
+                       if (value >= vbar.Minimum && value <= vbar.Maximum)
+                               vbar.Value = value;
+               }
 
-                       if (e.NewSelection.GridItemType == GridItemType.Property) {
-                               if (e.NewSelection.PropertyDescriptor != null) {
+               internal void SelectItem (GridEntry oldItem, GridEntry newItem) 
+               {
+                       if (oldItem != null)
+                               InvalidateItemLabel (oldItem);
+                       if (newItem != null) {
+                               UpdateItem (newItem);
+                               ScrollToItem (newItem);
+                       } else
+                               grid_textbox.Visible = false;
+               }
 
-                                       if (e.NewSelection.Value == null)
-                                               grid_textbox.Text = "";
-                                       else
-                                               grid_textbox.Text = e.NewSelection.PropertyDescriptor.Converter.ConvertToString(e.NewSelection.Value);
-                                       if (((GridEntry)e.NewSelection).CanResetValue ())
-                                               grid_textbox.Font = bold_font;
-                                       else
-                                               grid_textbox.Font = this.Font;
+               internal void UpdateView ()
+               {
+                       UpdateScrollBar ();
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate ();
+                       Update ();
+               }
 
-                                       grid_textbox_Show (e.NewSelection);
-                               }
-                       }
-                       else {
-                               grid_textbox_Hide ();
-                       }
+               internal void ExpandItem (GridEntry item)
+               {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
-               private void PropertyValueChanged(object s, PropertyValueChangedEventArgs e) {
-                       if (e.ChangedItem.PropertyDescriptor != null) {
-                               grid_textbox.Text = e.ChangedItem.PropertyDescriptor.Converter.ConvertToString(e.ChangedItem.Value);
-                               if (((GridEntry)e.ChangedItem).CanResetValue())
-                                       grid_textbox.Font = bold_font;
-                               else
-                                       grid_textbox.Font = this.Font;
-                       }
+               internal void CollapseItem (GridEntry item)
+               {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
-               private void DropDownControl(Control control, bool block) {
+               private void ShowDropDownControl (Control control, bool block) 
+               {
                        Object  queue_id;
 
                        Form owner = FindForm ();
@@ -1051,40 +921,64 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        Point location;
                        dropdown_form.Size = control.Size;
                        control.Dock = DockStyle.Fill;
-                       dropdown_form.Controls.Clear();
-                       dropdown_form.Controls.Add(control);
-                       dropdown_form.Location = PointToScreen (new Point (SplitterLocation, grid_textbox.Location.Y + row_height));
+                       dropdown_form.Controls.Add (control);
+                       dropdown_form.Width = Math.Max (ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0), 
+                                                       control.Width);
+                       dropdown_form.Location = PointToScreen (new Point (grid_textbox.Right - control.Width, grid_textbox.Location.Y + row_height));
+                       RepositionInScreenWorkingArea (dropdown_form);
                        location = dropdown_form.Location;
 
-                       dropdown_form.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0);
-
                        owner.AddOwnedForm (dropdown_form);
 
-                       dropdown_form.Show();
+                       dropdown_form.Show ();
 
                        if (dropdown_form.Location != location) {
                                dropdown_form.Location = location;
                        }
                        if (block) {
-                               System.Windows.Forms.MSG msg = new MSG();
-                               queue_id = XplatUI.StartLoop(Thread.CurrentThread);
-                               while (dropdown_form.Visible && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) {
-
-                                       if ((msg.message == Msg.WM_NCLBUTTONDOWN ||
-                                            msg.message == Msg.WM_NCMBUTTONDOWN ||
-                                            msg.message == Msg.WM_NCRBUTTONDOWN ||
-                                            msg.message == Msg.WM_LBUTTONDOWN ||
-                                            msg.message == Msg.WM_MBUTTONDOWN ||
-                                            msg.message == Msg.WM_RBUTTONDOWN)
-                                           && !HwndInControl (dropdown_form, msg.hwnd)) {
-                                               CloseDropDown ();
+                               System.Windows.Forms.MSG msg = new MSG ();
+                               queue_id = XplatUI.StartLoop (Thread.CurrentThread);
+                               while (dropdown_form.Visible && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) {
+                                       switch (msg.message) {
+                                               case Msg.WM_NCLBUTTONDOWN:
+                                           case Msg.WM_NCMBUTTONDOWN:
+                                           case Msg.WM_NCRBUTTONDOWN:
+                                           case Msg.WM_LBUTTONDOWN:
+                                           case Msg.WM_MBUTTONDOWN:
+                                           case Msg.WM_RBUTTONDOWN:
+                                               if (!HwndInControl (dropdown_form, msg.hwnd))
+                                                               CloseDropDown ();
                                                break;
+                                               case Msg.WM_ACTIVATE:
+                                               case Msg.WM_NCPAINT:
+                                                       if (owner.window.Handle == msg.hwnd)
+                                                               CloseDropDown ();
+                                               break;                                          
                                        }
-                                       XplatUI.TranslateMessage(ref msg);
-                                       XplatUI.DispatchMessage(ref msg);
+                                       XplatUI.TranslateMessage (ref msg);
+                                       XplatUI.DispatchMessage (ref msg);
+                               }
+                               XplatUI.EndLoop (Thread.CurrentThread);                 
+                       }
+               }
+
+               private void RepositionInScreenWorkingArea (Form form)
+               {
+                       Rectangle workingArea = Screen.FromControl (form).WorkingArea;
+                       if (!workingArea.Contains (form.Bounds)) {
+                               int x, y;
+                               x = form.Location.X;
+                               y = form.Location.Y;
+
+                               if (form.Location.X < workingArea.X)
+                                       x = workingArea.X;
+
+                               if (form.Location.Y + form.Size.Height > workingArea.Height) {
+                                       Point aboveTextBox = PointToScreen (new Point (grid_textbox.Right - form.Width, grid_textbox.Location.Y));
+                                       y = aboveTextBox.Y - form.Size.Height;
                                }
 
-                               property_grid.PropertyValueChangedInternal ();
+                               form.Location = new Point (x, y);
                        }
                }
 
@@ -1092,28 +986,29 @@ namespace System.Windows.Forms.PropertyGridInternal {
                {
                        if (hwnd == c.window.Handle)
                                return true;
-                       foreach (Control cc in c.Controls.GetAllControls ())
+                       foreach (Control cc in c.Controls.GetAllControls ()) {
                                if (HwndInControl (cc, hwnd))
                                        return true;
+                       }
                        return false;
                }
-
                #endregion
 
                #region IWindowsFormsEditorService Members
 
-               public void CloseDropDown() {
+               public void CloseDropDown () {
                        Control c = dropdown_form.Controls[0];
                        c.Capture = false;
-                       dropdown_form.Hide();
+                       dropdown_form.Hide ();
+                       dropdown_form.Controls.Clear ();
                }
 
-               public void DropDownControl(Control control) {
-                       DropDownControl (control, true);
+               public void DropDownControl (Control control) {
+                       ShowDropDownControl (control, true);
                }
 
-               public System.Windows.Forms.DialogResult ShowDialog(Form dialog) {
-                       return dialog.ShowDialog(this);
+               public System.Windows.Forms.DialogResult ShowDialog (Form dialog) {
+                       return dialog.ShowDialog (this);
                }
 
                #endregion