Automatic Expandable Properties in a PropertyGrid





2.00/5 (3 votes)
Jan 4, 2006
4 min read

73076

1989
The article describes a family of classes that will automatically enable each of your custom-type's public properties to be expandable in a PropertyGrid without the need to write an explicit TypeConverter. You will also be able to edit those properties that support the 'set' accessor.
Introduction
This article explains adding PropertyGrid
support to your custom-types without an associated TypeConverter
.
When I finally bit the bullet and moved from Visual Studio 2002 up to Visual Studio 2005, I was disappointed (to put it mildly) to discover that when I selected an instance of my Form
-class into a PropertyGrid
, none of my custom-type public properties were either expandable or editable as (I am sure!) they used to be. All I could see for each of my properties was a single, relatively useless GridItem
in grey-text showing <namespace>.<type-name>.
Of course, by overriding ToString()
in each of my custom-types, I could have made the display a little more aesthetically pleasing, I could even display the type’s fields and properties using this approach. However, this wouldn’t have allowed any of those objects to be edited, or even indicate which one’s were editable and which were read-only. Surely, the most useful feature of PropertyGrid
a'la 2002 was the way it allowed you to very rapidly provide a type-editor/inspector for your custom-types.
Initially, I spent a day, or so, decorating my classes and their members with various combinations of ComponentModel
attribute-tags, in an attempt to get the behaviour that:
- I wanted, and
- the attribute-names suggested they would provide.
Hah! There followed then a very painful 3-4 days scouring MSDN, forums, etc., initially trying to discover Microsoft’s explanation for the change in behaviour and an associated work-around (fat chance!); then, when this search proved fruitless, to find someone else who had hit and, more importantly solved the same problem. I didn’t have much luck. I did find a few posts on various sites from one Dev. Manager in the US who had been through the same thing back in June this year, but when I mailed him to ask about a solution, he wrote back and said he’d given-up and gone another route.
Finally, I began to realize, although I admit, it took some time for me to accept it, that the only solution (according to Microsoft documentation at least) was to write a custom TypeConverter
for every one of my custom-property types! This would enable PropertyGrid
to see each custom-type as the aggregation of subtypes that I wanted. This seemed like a pretty big ask!
Then I found Stephen Toub’s excellent NetMatters articles: see URLs below in Background.
- NET Matters ICustomTypeDescriptor, Part 1 -- MSDN Magazine, April 2005
- NET Matters ICustomTypeDescriptor, Part 2 -- MSDN Magazine, May 2005
…in which he introduces a family of classes: FieldsToPropertiesTypeDescriptor
, FieldsToPropertiesTypeDescriptorProvider
, etc., whose purpose is, given an existing type MyClass
(say) that exposes only public-access fields (i.e. no Property support), to automatically wrap each field in a pseudo-property that will display in a PropertyGrid
without your having to modify the original MyClass
at all.
I would encourage anyone interested in PropertyGrid
to read these two articles to gain a better understanding of its internal operation; also, to help understand the code presented here.
Although FieldsToPropertiesTypeDescriptor
, et. al. didn’t quite provide the desired behaviour, it was possible to use the same technique and architecture to create a solution to my own particular problem. The results are presented below as ExpandableObject
and ExpandablePropertiesTypeDescriptionProvider
.
Note that the cache-mechanism used in ExpandableObject
, in addition to the basic architecture, is lifted from the code in Stephen Taub’s article. Thanks to the author for the information/techniques covered therein and permission to reuse for non-profit making purposes.
Background
Recommended reading:
- NET Matters ICustomTypeDescriptor, Part 1 -- MSDN Magazine, April 2005
- NET Matters ICustomTypeDescriptor, Part 2 -- MSDN Magazine, May 2005
Using the code
To add support for PropertyGrid
expandable/editable public properties to your class, simply derive it from ExpandableObject
, e.g.:
using ExpandablePropertiesTypeDescriptor;
public class MyCustomType : ExpandableObject
{
private int myIntField = 0;
public int MyIntProperty
{
get{ . . . }
set{ . . . }
}
...
}
Now, when you select an instance of MyCustomType
into a PropertyGrid
, e.g.:
propertyGrid1.SelectedObject = MyCustomTypeInstance;
you will see all its public-access properties displayed under the usual [+] widget. Any property that supports ‘set
’ will also be editable in the PropertyGrid
.
Note that, if it is not convenient for you to inherit from ExpandableObject
, e.g., the object that you want to select in PropertyGrid
is a Form
(say) and you want the PropertyGrid
to display its (the Form
’s) public properties, you can do the following:
using ExpandablePropertiesTypeDescriptor;
public partial class MyFormClass : Form
{
public MyFormClass()
{
TypeDescriptor.AddProvider(new
ExpandablePropertiesTypeDescriptionProvider(GetType()),
this);
InitializeComponent();
}
}
Important!
If you use the scenario shown above, be sure to call TypeDescriptor.RemoveProvider
before your application closes. You can do this in the Form
's Dispose()
method as follows:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
TypeDescriptor.RemoveProvider(new
ExpandablePropertiesTypeDescriptionProvider(GetType()),
this);
base.Dispose(disposing);
}
Points of Interest
Check-out the ExpandableObjectDemo.DemoForm
to see the ExpandableObject
used on a custom-type property owned by a form. Notice that both techniques [described above] are used, i.e., ExpandableObjectDemo.CustomType
inherits from ExpandableObject
whilst ExpandableObjectDemo.DemoForm
calls TypeDescriptor.AddProvider
/ TypeDescriptor.RemoveProvider
. This is because it is the Form
object that is selected in PropertyGrid
. If we only wanted to display ExpandableObjectDemo.CustomType
in the PropertyGrid
without showing its relationship to the parent object, we need not call the Add
/RemoveProvider
in the Form
object.
I guess the most important lesson I have (re)learned during this episode was: “Don’t mess with your dev. environment unless you (i) enjoy pain and (ii) have nothing better [or more urgent] to do.