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:
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.