2007-01-03 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGrid.cs
index 5a591a1117e7d233d4e1b28e14428265848786d0..5646d06d53211f45fddbab352f632bce1a76938c 100644 (file)
@@ -32,11 +32,16 @@ using System.ComponentModel;
 using System.Collections;
 using System.ComponentModel.Design;
 using System.Reflection;
+using System.Runtime.InteropServices;
 using System.Windows.Forms.Design;
 using System.Windows.Forms.PropertyGridInternal;
 
 namespace System.Windows.Forms {
        [Designer("System.Windows.Forms.Design.PropertyGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+#if NET_2_0
+       [ClassInterface (ClassInterfaceType.AutoDispatch)]
+       [ComVisible (true)]
+#endif
        public class PropertyGrid : System.Windows.Forms.ContainerControl, ComponentModel.Com2Interop.IComPropertyBrowser {
                #region Private Members
                
@@ -57,7 +62,7 @@ namespace System.Windows.Forms {
                private PropertySort property_sort;
                private PropertyTabCollection property_tabs;
                private GridItem selected_grid_item;
-               internal GridItemCollection grid_items;
+               internal GridItem root_grid_item;
                private object[] selected_objects;
                private PropertyTab selected_tab;
 
@@ -73,7 +78,6 @@ namespace System.Windows.Forms {
                internal Panel help_panel;
                internal Label help_title_label;
                internal Label help_description_label;
-               private ContextMenu context_menu;
                private MenuItem reset_menuitem;
                private MenuItem description_menuitem;
                private object current_property_value;
@@ -82,8 +86,7 @@ namespace System.Windows.Forms {
                
                #region Contructors
                public PropertyGrid() {
-                       selected_objects = new object[1];
-                       grid_items = new GridItemCollection();
+                       selected_objects = new object[0];
                        property_tabs = new PropertyTabCollection();
 
                        line_color = SystemColors.ScrollBar;
@@ -108,7 +111,6 @@ namespace System.Windows.Forms {
                        help_title_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                        help_title_label.Name = "help_title_label";
                        help_title_label.Font = new Font(this.Font,FontStyle.Bold);
-                       help_title_label.Text = "Title";
                        help_title_label.Location = new Point(2,2);
                        help_title_label.Height = 17;
                        help_title_label.Width = help_panel.Width - 4;
@@ -118,10 +120,9 @@ namespace System.Windows.Forms {
                        help_description_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                        help_description_label.Name = "help_description_label";
                        help_description_label.Font = this.Font;
-                       help_description_label.Text = "The long important Description";
                        help_description_label.Location = new Point(2,help_title_label.Top+help_title_label.Height);
                        help_description_label.Width = help_panel.Width - 4;
-                       help_description_label.Height = 17;
+                       help_description_label.Height = help_panel.Height - help_description_label.Top - 2;
 
                        help_panel.Controls.Add(help_description_label);
                        help_panel.Controls.Add(help_title_label);
@@ -133,7 +134,7 @@ namespace System.Windows.Forms {
                        alphabetic_toolbarbutton = new ToolBarButton();
                        separator_toolbarbutton = new ToolBarButton();
                        propertypages_toolbarbutton = new ToolBarButton();
-                       context_menu = new ContextMenu();
+                       ContextMenu context_menu = new ContextMenu();
 
                        toolbar_imagelist = new ImageList();
                        toolbar_imagelist.ColorDepth = ColorDepth.Depth32Bit;
@@ -145,12 +146,11 @@ namespace System.Windows.Forms {
 
                        toolbar.Appearance = ToolBarAppearance.Flat;
                        toolbar.AutoSize = false;
-                       toolbar.Buttons.AddRange(new ToolBarButton[] {
-                                                                                                                        categorized_toolbarbutton,
-                                                                                                                        alphabetic_toolbarbutton,
-                                                                                                                        separator_toolbarbutton,
-                                                                                                                        propertypages_toolbarbutton});
-
+                       toolbar.Buttons.AddRange(new ToolBarButton[] {categorized_toolbarbutton,
+                                                                     alphabetic_toolbarbutton,
+                                                                     separator_toolbarbutton,
+                                                                     propertypages_toolbarbutton});
+                       
                        toolbar.ButtonSize = new System.Drawing.Size(20, 20);
                        toolbar.ImageList = toolbar_imagelist;
                        toolbar.Location = new System.Drawing.Point(0, 0);
@@ -161,11 +161,11 @@ namespace System.Windows.Forms {
 
                        categorized_toolbarbutton.ImageIndex = 0;
                        categorized_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
-                       categorized_toolbarbutton.ToolTipText = (string)Locale.GetResource( "Categorized");
+                       categorized_toolbarbutton.ToolTipText = Locale.GetText ("Categorized");
 
                        alphabetic_toolbarbutton.ImageIndex = 1;
                        alphabetic_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
-                       alphabetic_toolbarbutton.ToolTipText = (string)Locale.GetResource( "Alphabetic");
+                       alphabetic_toolbarbutton.ToolTipText = Locale.GetText ("Alphabetic");
 
                        separator_toolbarbutton.Style = ToolBarButtonStyle.Separator;
 
@@ -287,7 +287,7 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [BrowsableAttribute(false)]
+               [BrowsableAttribute (false)]
                [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
                public virtual bool CommandsVisible {
                        get {
@@ -295,7 +295,11 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [DefaultValue(false)]
+#if NET_2_0
+               [DefaultValue (true)]
+#else
+               [DefaultValue (false)]
+#endif
                public virtual bool CommandsVisibleIfAvailable {
                        get {
                                return commands_visible_if_available;
@@ -338,6 +342,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [Control]")]
+#endif
                public Color HelpBackColor {
                        get {
                                return help_panel.BackColor;
@@ -351,6 +358,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [ControlText]")]
+#endif
                public Color HelpForeColor {
                        get {
                                return help_panel.ForeColor;
@@ -381,6 +391,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue (false)]
+#endif
                public bool LargeButtons {
                        get {
                                return large_buttons;
@@ -395,6 +408,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [InactiveBorder]")]
+#endif
                public Color LineColor {
                        get {
                                return line_color;
@@ -425,13 +441,14 @@ namespace System.Windows.Forms {
                                }
 
                                property_sort = value;
-                               
+
+                               UpdateToolBarButtons();
                                ReflectObjects();
                                property_grid_view.Refresh();
-                               
-                               if (PropertySortChanged != null) {
-                                       PropertySortChanged(this, EventArgs.Empty);
-                               }
+
+                               EventHandler eh = (EventHandler)(Events [PropertySortChangedEvent]);
+                               if (eh != null)
+                                       eh (this, EventArgs.Empty);
                        }
                }
 
@@ -464,12 +481,19 @@ namespace System.Windows.Forms {
                                        this.help_description_label.Text = selected_grid_item.PropertyDescriptor.Description;
                                        
                                current_property_value = value.Value;
-                               if (oldItem != null && oldItem.PropertyDescriptor != null)
-                                       oldItem.PropertyDescriptor.RemoveValueChanged(SelectedObject, new EventHandler(HandlePropertyValueChanged));
-                               if (selected_grid_item.PropertyDescriptor != null)
-                                       selected_grid_item.PropertyDescriptor.AddValueChanged(SelectedObject, new EventHandler(HandlePropertyValueChanged));
-                               OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs( oldItem, selected_grid_item));
-                               
+                               if (oldItem != null && oldItem.PropertyDescriptor != null) {
+                                       for (int i = 0; i < ((GridEntry)oldItem).SelectedObjects.Length; i ++) {
+                                               object target = GetTarget (oldItem, i);
+                                               oldItem.PropertyDescriptor.RemoveValueChanged(target, new EventHandler(HandlePropertyValueChanged));
+                                       }
+                               }
+                               if (selected_grid_item.PropertyDescriptor != null) {
+                                       for (int i = 0; i < ((GridEntry)selected_grid_item).SelectedObjects.Length; i ++) {
+                                               object target = GetTarget (selected_grid_item, i);
+                                               selected_grid_item.PropertyDescriptor.AddValueChanged(target, new EventHandler(HandlePropertyValueChanged));
+                                       }
+                               }
+                               OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs (oldItem, selected_grid_item));
                        }
                }
 
@@ -481,22 +505,17 @@ namespace System.Windows.Forms {
                [TypeConverter("System.Windows.Forms.PropertyGrid+SelectedObjectConverter, " + Consts.AssemblySystem_Windows_Forms)]
                public object SelectedObject {
                        get {
-                               return selected_objects[0];
+                               if (selected_objects.Length > 0)
+                                       return selected_objects[0];
+                               return null;
                        }
 
                        set {
-                               selected_objects = new object[] {value};
-                               if (this.SelectedObject == null)
-                                       return;
-                               PropertyTabAttribute[] propTabs = (PropertyTabAttribute[])this.SelectedObject.GetType().GetCustomAttributes(typeof(PropertyTabAttribute),true);
-                               if (propTabs.Length > 0) {
-                                       foreach (Type tabType in propTabs[0].TabClasses) {
-                                               this.PropertyTabs.AddTabType(tabType);
-                                       }
-                               }
-                               RefreshTabs(PropertyTabScope.Component);
-                               ReflectObjects();
-                               property_grid_view.Refresh();
+                               if (value == null)
+                                       SelectedObjects = new object[0];
+                               else
+                                       SelectedObjects = new object[] {value};
+
                        }
                }
 
@@ -508,8 +527,33 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               selected_objects = value;
+                               if (value != null) {
+                                       for (int i = 0; i < value.Length; i++) {
+                                               if (value [i] == null)
+                                                       throw new ArgumentException (String.Format ("Item {0} in the objs array is null.", i));
+                                       }
+                                       selected_objects = value;
+                               } else {
+                                       selected_objects = new object [0];
+                               }
+
+                               if (selected_objects.Length > 0) {
+                                       PropertyTabAttribute[] propTabs = (PropertyTabAttribute[])this.SelectedObject.GetType().GetCustomAttributes(typeof(PropertyTabAttribute),true);
+                                       if (propTabs.Length > 0) {
+                                               foreach (Type tabType in propTabs[0].TabClasses) {
+                                                       this.PropertyTabs.AddTabType(tabType);
+                                               }
+                                       }
+                               }
+
+                               RefreshTabs(PropertyTabScope.Component);
                                ReflectObjects();
+                               if (root_grid_item != null) {
+                                       /* find the first non category grid item and select it */
+                                       SelectedGridItem = FindFirstItem (root_grid_item);
+                               }
+                               property_grid_view.Refresh();
+                               OnSelectedObjectsChanged (EventArgs.Empty);
                        }
                }
 
@@ -548,6 +592,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [Window]")]
+#endif
                public Color ViewBackColor {
                        get {
                                return property_grid_view.BackColor;
@@ -562,6 +609,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [WindowText]")]
+#endif
                public Color ViewForeColor {
                        get {
                                return property_grid_view.ForeColor;
@@ -621,16 +671,22 @@ namespace System.Windows.Forms {
                protected override void Dispose(bool val) {
                        base.Dispose(val);
                }
-               
+
+               [MonoTODO ("should this be recursive?  or just the toplevel items?")]
                public void CollapseAllGridItems () {
-                       foreach (GridItem item in this.grid_items) {
-                               item.Expanded = false;
+                       if (root_grid_item != null) {
+                               foreach (GridItem item in root_grid_item.GridItems) {
+                                       item.Expanded = false;
+                               }
                        }
                }
 
+               [MonoTODO ("should this be recursive?  or just the toplevel items?")]
                public void ExpandAllGridItems () {
-                       foreach (GridItem item in this.grid_items) {
-                               item.Expanded = true;
+                       if (root_grid_item != null) {
+                               foreach (GridItem item in root_grid_item.GridItems) {
+                                       item.Expanded = true;
+                               }
                        }
                }
 
@@ -674,8 +730,11 @@ namespace System.Windows.Forms {
                }
                
                [MonoTODO]
-               protected void OnComComponentNameChanged(ComponentRenameEventArgs e) {
-                       throw new NotImplementedException();
+               protected void OnComComponentNameChanged(ComponentRenameEventArgs e)
+               {
+                       ComponentRenameEventHandler eh = (ComponentRenameEventHandler)(Events [ComComponentNameChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected override void OnFontChanged(EventArgs e) {
@@ -721,8 +780,9 @@ namespace System.Windows.Forms {
                }
 
                protected virtual void OnPropertyValueChanged (PropertyValueChangedEventArgs e) {
-                       if (PropertyValueChanged != null) {
-                               PropertyValueChanged(this, e);
+                       PropertyValueChangedEventHandler eh = (PropertyValueChangedEventHandler)(Events [PropertyValueChangedEvent]);
+                       if (eh != null) {
+                               eh (this, e);
                                current_property_value = selected_grid_item.Value;
                        }
                }
@@ -732,15 +792,15 @@ namespace System.Windows.Forms {
                }
 
                protected virtual void OnSelectedGridItemChanged (SelectedGridItemChangedEventArgs e) {
-                       if (SelectedGridItemChanged != null) {
-                               SelectedGridItemChanged(this, e);
-                       }
+                       SelectedGridItemChangedEventHandler eh = (SelectedGridItemChangedEventHandler)(Events [SelectedGridItemChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected virtual void OnSelectedObjectsChanged (EventArgs e) {
-                       if (SelectedObjectsChanged != null) {
-                               SelectedObjectsChanged(this, e);
-                       }
+                       EventHandler eh = (EventHandler)(Events [SelectedObjectsChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected override void OnSystemColorsChanged (EventArgs e) {
@@ -755,6 +815,7 @@ namespace System.Windows.Forms {
                        return base.ProcessDialogKey (keyData);
                }
 
+               [EditorBrowsable (EditorBrowsableState.Never)]
                protected override void ScaleCore (float dx, float dy) {
                        base.ScaleCore (dx, dy);
                }
@@ -770,11 +831,36 @@ namespace System.Windows.Forms {
                #endregion
 
                #region Events
-               public event EventHandler PropertySortChanged;
-               public event PropertyTabChangedEventHandler PropertyTabChanged;
-               public event PropertyValueChangedEventHandler PropertyValueChanged;
-               public event SelectedGridItemChangedEventHandler SelectedGridItemChanged;
-               public event EventHandler SelectedObjectsChanged;
+               static object PropertySortChangedEvent = new object ();
+               static object PropertyTabChangedEvent = new object ();
+               static object PropertyValueChangedEvent = new object ();
+               static object SelectedGridItemChangedEvent = new object ();
+               static object SelectedObjectsChangedEvent = new object ();
+
+               public event EventHandler PropertySortChanged {
+                       add { Events.AddHandler (PropertySortChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertySortChangedEvent, value); }
+               }
+
+               public event PropertyTabChangedEventHandler PropertyTabChanged {
+                       add { Events.AddHandler (PropertyTabChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertyTabChangedEvent, value); }
+               }
+
+               public event PropertyValueChangedEventHandler PropertyValueChanged {
+                       add { Events.AddHandler (PropertyValueChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertyValueChangedEvent, value); }
+               }
+
+               public event SelectedGridItemChangedEventHandler SelectedGridItemChanged {
+                       add { Events.AddHandler (SelectedGridItemChangedEvent, value); }
+                       remove { Events.RemoveHandler (SelectedGridItemChangedEvent, value); }
+               }
+
+               public event EventHandler SelectedObjectsChanged {
+                       add { Events.AddHandler (SelectedObjectsChangedEvent, value); }
+                       remove { Events.RemoveHandler (SelectedObjectsChangedEvent, value); }
+               }
                
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -824,11 +910,10 @@ namespace System.Windows.Forms {
                        throw new NotImplementedException();
                }
 
-               [MonoTODO]
-               private event ComponentRenameEventHandler com_component_name_changed;
+               static object ComComponentNameChangedEvent = new object ();
                event ComponentRenameEventHandler ComponentModel.Com2Interop.IComPropertyBrowser.ComComponentNameChanged {
-                       add { com_component_name_changed += value; }
-                       remove { com_component_name_changed -= value; }
+                       add { Events.AddHandler (ComComponentNameChangedEvent, value); }
+                       remove { Events.RemoveHandler (ComComponentNameChangedEvent, value); }
                }
                #endregion      // Com2Interop.IComPropertyBrowser Interface
 
@@ -906,6 +991,21 @@ namespace System.Windows.Forms {
 
                #region Private Helper Methods
 
+               private GridItem FindFirstItem (GridItem root)
+               {
+                       if (root.GridItemType == GridItemType.Property)
+                               return root;
+
+                       foreach (GridItem item in root.GridItems) {
+                               GridItem subitem = FindFirstItem (item);
+                               if (subitem != null)
+                                       return subitem;
+                       }
+
+                       return null;
+               }
+
+
                private void toolbar_ButtonClick (object sender, ToolBarButtonClickEventArgs e) {
                        if (e.Button == alphabetic_toolbarbutton) {
                                this.PropertySort = PropertySort.Alphabetical;
@@ -913,9 +1013,6 @@ namespace System.Windows.Forms {
                        else if (e.Button == categorized_toolbarbutton) {
                                this.PropertySort = PropertySort.Categorized;
                        }
-                       UpdateToolBarButtons();
-                       ReflectObjects();
-                       property_grid_view.Refresh();
                }
 
                internal void UpdateToolBarButtons () {
@@ -944,42 +1041,106 @@ namespace System.Windows.Forms {
                }
 
                private void ReflectObjects () {
-                       grid_items = new GridItemCollection();
-                       foreach (object obj in selected_objects) {
-                               if (obj != null) {
-                                       PopulateGridItemCollection(obj,grid_items, true);
+                       if (selected_objects.Length > 0) {
+                               root_grid_item = new RootGridEntry (property_grid_view,
+                                                                   selected_objects.Length > 1 ? selected_objects : selected_objects[0]);
+                                                                          
+                               PopulateMergedGridItems (selected_objects, root_grid_item.GridItems, true, root_grid_item);
+                       }
+               }
+
+               private void PopulateMergedGridItems (object[] objs, GridItemCollection grid_item_coll, bool recurse, GridItem parent_grid_item)
+               {
+                       ArrayList intersection = null;
+
+                       for (int i = 0; i < objs.Length; i ++) {
+                               if (objs [i] == null)
+                                       continue;
+
+                               ArrayList new_intersection = new ArrayList ();
+                               Type type = objs[i].GetType();
+
+                               /* i tried using filter attributes, but there's no way to do it for EditorBrowsableAttributes,
+                                  since that type lacks an override for IsDefaultAttribute, and for some reason the
+                                  BrowsableAttribute.Yes filter wasn't working */
+                               PropertyDescriptorCollection properties = null;
+
+                               if (typeof (ICustomTypeDescriptor).IsAssignableFrom (type)) {
+                                       properties = ((ICustomTypeDescriptor)objs[i]).GetProperties ();
+                               }
+                               if (properties == null) {
+                                       TypeConverter cvt = TypeDescriptor.GetConverter (objs[i]);
+                                       properties = cvt.GetProperties (objs[i]);
+                               }
+                               if (properties == null) {
+                                       properties = TypeDescriptor.GetProperties (objs[i]);
+                               }
+
+                               foreach (PropertyDescriptor p in (i == 0 ? (ICollection)properties : (ICollection)intersection)) {
+                                       PropertyDescriptor property = (i == 0 ? p : properties [p.Name]);
+                                       if (property == null) {
+                                               /* since the property doesn't exist in at least one of the other types, 
+                                                  exclude it */
+                                       }
+                                       else if (!property.IsBrowsable
+                                           || (objs.Length > 1 && property.Attributes.Contains (MergablePropertyAttribute.No))
+                                           || property.Attributes.Contains (new EditorBrowsableAttribute (EditorBrowsableState.Never))
+                                           || property.Attributes.Contains (new EditorBrowsableAttribute (EditorBrowsableState.Advanced))) {
+                                               /* if the property isn't supposed to be displayed in the merged view,
+                                                  excluded it */
+                                       }
+                                       else {
+                                               Type p_type = p.ComponentType;
+                                               Type property_type = property.ComponentType;
+
+                                               if (p_type.IsAssignableFrom (type))
+                                                       new_intersection.Add (p);
+                                               else if (property_type.IsAssignableFrom (p_type))
+                                                       new_intersection.Add (property);
+                                       }
                                }
+
+                               intersection = new_intersection;
                        }
+
+                       if (intersection != null && intersection.Count > 0)
+                               PopulateGridItemsFromProperties (objs, intersection, grid_item_coll, recurse, parent_grid_item);
                }
 
-               private void PopulateGridItemCollection (object obj, GridItemCollection grid_item_coll, bool recurse) {
-                       if (!TypeDescriptor.GetConverter(obj).GetPropertiesSupported())
-                               return;
-                       PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(obj);
+               private void PopulateGridItemsFromProperties (object[] objs, ArrayList properties,
+                                                             GridItemCollection grid_item_coll, bool recurse, GridItem parent_grid_item) {
                        foreach (PropertyDescriptor property in properties) {
-                               if (property.IsBrowsable) {
-                                       GridEntry grid_entry = new GridEntry(obj, property);
-                                       if (property_sort == PropertySort.Alphabetical || !recurse) {
-                                               if (grid_item_coll[property.Name] == null)
-                                                       grid_item_coll.Add(property.Name,grid_entry);
-                                       }
-                                       else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) {
 
-                                               string category = property.Category;
-                                               GridItem cat_item = grid_item_coll[category];
-                                               if (cat_item == null) {
-                                                       cat_item = new CategoryGridEntry(category);
-                                                       grid_item_coll.Add(category,cat_item);
-                                               }
-                                               cat_item.GridItems.Add(property.Name,grid_entry);
+                               GridEntry grid_entry = new GridEntry (property_grid_view, objs, property);
+                               grid_entry.SetParent (parent_grid_item);
+                               if (property_sort == PropertySort.Alphabetical || /* XXX */property_sort == PropertySort.NoSort || !recurse) {
+                                       if (grid_item_coll[property.Name] == null) {
+                                               grid_item_coll.Add(property.Name,grid_entry);
+                                               grid_entry.SetParent ((GridEntry)parent_grid_item);
                                        }
-                                       if (recurse) {
-                                               object propObj = property.GetValue(obj);
-                                               if (propObj != null)
-                                                       PopulateGridItemCollection(propObj,grid_entry.GridItems, false);
+                               }
+                               else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) {
+
+                                       string category = property.Category;
+                                       CategoryGridEntry cat_item = grid_item_coll[category] as CategoryGridEntry;
+                                       if (cat_item == null) {
+                                               cat_item = new CategoryGridEntry (property_grid_view, category);
+                                               cat_item.SetParent (parent_grid_item);
+                                               grid_item_coll.Add (category, cat_item);
                                        }
-                                       grid_entry.Expanded = false;
+                                       if (cat_item.GridItems[property.Name] == null) {
+                                               cat_item.GridItems.Add(property.Name,grid_entry);
+                                               grid_entry.SetParent (cat_item);
+                                       }
+                               }
+
+                               if (recurse && property.Converter != null && property.Converter.GetPropertiesSupported()) {
+                                       object[] subobjs = new object[objs.Length];
+                                       for (int i = 0; i < objs.Length; i ++)
+                                               subobjs[i] = property.GetValue (objs[i]);
+                                       PopulateMergedGridItems (subobjs, grid_entry.GridItems, false, grid_entry);
                                }
+                               grid_entry.Expanded = false;
                        }
                }
 
@@ -988,11 +1149,24 @@ namespace System.Windows.Forms {
                        e.Graphics.DrawRectangle(SystemPens.ControlDark, 0,0,help_panel.Width-1,help_panel.Height-1 );
                }
 
+               internal object GetTarget (GridItem item, int selected_index)
+               {
+                       object target = ((GridEntry)item).SelectedObjects[selected_index];
+
+                       while (item.Parent != null && item.Parent.GridItemType != GridItemType.Property)
+                               item = item.Parent;
+
+                       if (item.Parent != null && item.Parent.PropertyDescriptor != null)
+                               target = item.Parent.PropertyDescriptor.GetValue (((GridEntry)item.Parent).SelectedObjects[selected_index]);
+
+                       return target;
+               }
                #endregion      // Private Helper Methods
 
 
 #if NET_2_0
 
+               [DefaultValue (false)]
                public bool UseCompatibleTextRendering {
                        get {
                                return use_compatible_text_rendering;
@@ -1007,7 +1181,12 @@ namespace System.Windows.Forms {
                // as we can not change the color for BorderStyle.FixedSingle and we need the correct
                // ClientRectangle so that the ScrollBar doesn't draw over the border we need this class
                internal class BorderHelperControl : Control {
-                       
+
+                       public BorderHelperControl ()
+                       {
+                               BackColor = ThemeEngine.Current.ColorWindow;
+                       }
+
                        protected override void OnPaint (PaintEventArgs e)
                        {
                                e.Graphics.DrawRectangle (SystemPens.ControlDark, 0 , 0 , Width - 1, Height - 1);
@@ -1024,8 +1203,6 @@ namespace System.Windows.Forms {
                                        
                                        control.Width = ClientRectangle.Width - 2;
                                        control.Height = ClientRectangle.Height - 2;
-                                       
-                                       Refresh ();
                                }
                                base.OnSizeChanged (e);
                        }
@@ -1034,5 +1211,11 @@ namespace System.Windows.Forms {
                // needed! this little helper makes it possible to draw a different toolbar border
                // and toolbar backcolor in ThemeWin32Classic
                internal class PropertyToolBar : ToolBar {}
+
+
+               [MonoTODO ("not sure what this class does, but it's listed as a type converter for a property in this class, and this causes problems if it's not present")]
+               internal class SelectedObjectConverter : TypeConverter
+               {
+               }
        }
 }