Design-Time Integration—Expandable Object Converter
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
| CSharp-Online.NET:Articles |
| C# Articles |
| © 2004 Chris Sells |
Expandable Object Converter
Although using the UI shown in Figure 9.23 is better than not being able to edit the property at all, there are still ways it can be improved. For instance, put yourself in a developer's shoes. Although it might be obvious what the first part of the property is, it's disappointing not to be able to pick the color from one of those pretty drop-down color pickers. And what is the second part of the property meant to be? Length, width, degrees, something else?
As an example of what you'd like to see, the Font type supports browsing and editing of its subproperties, as shown in Figure 9.24.

Figure 9.24. Expanded Property Value
This ability to expand a property of a custom type makes it a lot easier to understand what the property represents and what sort of values you need to provide. To allow subproperty editing, you simply change the base type from TypeConverter to ExpandableObjectConverter (from the System.ComponentModel namespace):
public class HandConverter : ExpandableObjectConverter { ... }
This change gives you multivalue and nested property editing support, as shown in Figure 9.25.

Figure 9.25. HandConverter Derived from ExpandableObjectConverter
Although you don't have to write any code to make this property expandable, you must write a little code to fix an irksome problem: a delay in property updating. In expanded mode, a change to the root property value is automatically reflected in the nested property value list. This occurs because the root property entry refers to the design-time property instance, whereas its nested property values refer to the design-time instance's properties directly, as illustrated in Figure 9.26.

Figure 9.26. Relationship between Root and Nested Properties and Design-Time Property Instance
When the root property is edited, the Property Browser calls HandConverter.ConvertFrom to convert the Property Browser's string entry to a new SecondHand instance, and that results in a refresh of the Property Browser. However, changing the nested values only changes the current instance's property values, rather than creating a new instance, and that doesn't result in an immediate refresh of the root property.
TypeConverters offer a mechanism you can use to force the creation of a new instance whenever instance property values change, something you achieve by overriding GetCreateInstanceSupported and CreateInstance. The GetCreateInstanceSupported method returns a Boolean indicating whether this support is available and, if it is, calls CreateInstance to implement it:
public class HandConverter : ExpandableObjectConverter { public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { // Always force a new instance return true; } public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues) { // Use the dictionary to create a new instance return new Hand( (Color)propertyValues["Color"], (int)propertyValues["Width"]); } ... }
If GetCreateInstanceSupported returns true, then CreateInstance will be used to create a new instance whenever any of the subproperties of an expandable object are changed. The propertyValues argument to CreateInstance provides a set of name/value pairs for the current values of the object's subproperties, and you can use them to construct a new instance.
|

