Make properties expandable in the Property Grid with ExpandableObjectConverter
System.ComponentModel.ExpandableObjectConverter converts
objects to expandable representations. It overrides GetProperties and
GetPropertiesSupported to expose properties through the GetProperties method of
the System.ComponentModel.TypeDescriptor class.
The ExpandableObjectConverter is simply a marker class that the
PropertyGrid uses to determine if it should expand the properties of an object.
For example, assume that your job is to implement the object model of a
vehicle, which can be designed on a Windows form. Also, for simplicity, assume
that a vehicle has a body style whose color can be customized. The model in
code would look like this:
namespaceTest
{
public class Vehicle
{
//
// Nested class which represents a vehicle's BodyStyle
//
public class BodyStyle
{
private Color _color = Color.Black;
[DefaultValue(typeof(System.Drawing.Color), "Black")]
public Color BodyColor
{
get
{
return _color;
}
set
{
_color = value;
}
}
}
private BodyStyle _body = new BodyStyle();
public BodyStyle Body
{
get
{
return _body;
}
}
}
}
You could display the properties of a vehicle in the PropertyGrid like this:
PropertyGrid propertyGrid = new PropertyGrid();
Vehicle honda = new Vehicle();
propertyGrid.SelectedObject = honda;
Here is how the PropertyGrid would look using the code above:

The text shown as the value of the Body property is the full name of the
property's type. Test is the namespace, while Vehicle+BodyStyle
represents the type of the Body property. The + sign indicates that the BodyStyle
type is nested within the Vehicle type. Because no type
converter was applied to the Body property or the BodyStyle type, the default
implementation of the PropertyGrid calls the property's ToString
method. Because ToString was not overridden in the BodyStyle
class, the Object class's ToString method
returns the type name.
Override ToString for the PropertyGrid
To allow the PropertyGrid to display useful text without applying a type
converter,
you must override the ToString method of BodyStyle,
as shown:
public override string ToString()
{
string body = "V-6";
if (_color.IsNamedColor)
{
body += " (" + _color.Name + ")";
}
return body;
}
Now, the PropertyGrid should look like this:

Notice that the text is shown correctly; however, there is still no way to
customize the color, as was stated in the requirements of the vehicle. This is
where ExpandableObjectConverter steps in.
Using the ExpandableObjectConverter class
You can apply any converter derived from TypeConverter to solve the
display name problem without having to override the ToString method. However,
the PropertyGrid still expects to see the ExpandableObjectConverter in the
attribute collection of an object in order for it to expand child properties
of that object. One way to apply this converter is to simply use the
TypeConverterAttribute, as shown here:
[TypeConverter(typeof(ExpandableObjectConverter))]
public class BodyStyle
Doing so will now yield a PropertyGrid like this:

However, there are times when you implement custom type converters that are
already applied to properties and types. It then makes sense to
derive your converter from ExpandableObjectConverter. But this may
sometimes be a nuissance. What if you had a hierarchy of type converters, and
what if your root converter was not supposed to support expanding
objects, due to some other rule. This might lead to a second root for only
expandable objects. Then, any base code for one converter must also be applied
to the other.
Conlusion
To me, it would have made more sense to have a special attribute, such as
ExpandableAttribute, that was used by the PropertyGrid to determine the
expandability of properties. It already takes advantage of various other
attributes: BrowsableAttribute, DefaultPropertyAttribute, CategoryAttribute,
and DescriptionAttribute to name a few. But for now, we must accept what is
there and use ExpandableObjectConverter to make our objects expandable in the
PropertyGrid.
Back to Tips and Tricks