Blog
Articles and information on C# and .NET development topics

In the first part of this article series, I described how to create a simple type converter for converting an object to and from a string. This follow up article expands upon that sample, to include more concise design time code generation, expandable property support and finally custom lists of values.

The examples in this article assume you are working from the original sample project from part 1.

Designer Code

When you place a Control or Component onto a design time surface such as a Form, the IDE will automatically generate any code required to initialize the object.

Modify the SampleClass class to inherit from Component then drop an instance onto the form and set the first property. Save the form, then open the designer file. You should see code something like this:

The designer has generated the source code required to populate the object by specifying each property individually. However, what happens if you wanted to set both properties at once or perhaps perform some other initialization code? We can use our type converter to solve this one.

Although slightly outside the bounds of this article, it's probably worth mentioning nonetheless. In the snippet above, you can see the Length2 and Length3 properties are explicitly assigned null, even though that is already the default value of these properties. If you're creating public facing library components it's always a good idea to apply the DefaultValue attribute to properties. It makes for cleaner code (if the value is the default value, no code will be generated) and allows other components to perform custom processing if required. For example, the PropertyGrid shows default properties in normal style, and non-default ones in bold.

Updating the Length class

Before we can adjust our type converter to support code generation, we need to extend our Length class by adding a new constructor.

I've added one constructor which will set both Value and Unit properties of the class. Due to the addition of a constructor with parameters, I now need to explicitly define a parameterless constructor as an implicit one will no longer be generated and I still want to be able to do new Length().

With these modifications in place, we can now dive into the type converter modifications.

CanConvertTo

The first thing we need to do is update our type converter to state that it supports the InstanceDescriptor class which is the mechanism the IDE will use for the custom code generation. We can do this by overriding a new method, CanConvertTo.

Update the LengthConverter class from the previous article to include the following:

This new overloads will inform the caller that we now support the InstanceDescriptor type, in addition to whatever the base TypeConverter can handle.

Extending ConvertTo

We briefly covered the ConvertTo override in the previous article in order to display our Length object as a string. Now that we have overridden CanConvertTo to state that we can handle additional types, we need to update this method as well.

The InstanceDescriptor class contains information needed to regenerate an object, and is comprised of two primary pieces of information.

A MemberInfo object which describes a method in the class. This can either be a constructor (which we'll use in our example), or something static that will return a new object - for example, Color.FromArgb.

An ICollection containing any of the arguments required to pass into the source member.

A warning on Visual Studio

While writing this article, Visual Studio frequently took a huff and refused to generate the design time code. I assume it is due to Visual Studio caching the assembly containing the TypeConverter, or it is another manifestation of not being able to unload managed assemblies without destroying the application domain. Whatever the reason, I found it quickly to be a source of frustration requiring frequent restarts of the IDE in order to pick up changed code.

As an experiment, I did a test where the Length and LengthConverter classes were in another assembly referenced in binary form. In this mode, I didn't have a single problem.

Finally, whereas basic conversions are easy to debug, the InstanceDescriptor conversion is much less so.

Something to bear in mind.

Expandable properties

Returning to the ExpandableObjectConverter and property expansion, that is trivially easy to add to your custom converter by overriding the GetPropertiesSupported and GetProperties methods.

First, by overriding GetPropertiesSupported we tell the caller that we support individual property editing. Then we can override GetProperties to return the actual properties to display.

In the above example, we return all available properties, which is probably normal behaviour. Let us assume the Length class has a property on it which we didn't want to see. We could return a different collection with that property filtered out:

The property grid honours the Browsable attribute - this is a much better way of controlling visibility of properties than the above!

Custom Values

The final example I want to demonstrate is custom values. Although you might assume that you'd have to create a custom UITypeEditor, if you just want a basic drop down list, you can do this directly from your type converter by overriding GetStandardValuesSupported and GetStandardValues.

First you need to override GetStandardValuesSupported in order to specify that we do support such values. Then in GetStandardValues we simply return the objects we want to see. In this example, I've generate 4 lengths which I return. When you run the program, you can see and select these values. Of course, you need to make sure that the values you return can be handled by the ConvertFrom method!

Summing up

Adding even an advanced type converter is still a easy task, and is something that can help enrich editing functionality.

About The Author

The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game. Until that time, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.

Leave a Comment

While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?

Reza Shamayel

Very thanks of you for this tutorial.
I study the part1 and part2 completely.
In the part2, you told that has a problem with IDE (under "A warning on Visual Studio" section).
I have same problem in my solution, exactly.
Whenever I save my solution and rebuild it, then change the property value, any try to save form, give me an error in IDE.
Error message tell me that my converter can not convert from my class to InstanceDescriptor.
Same error occur in your project exactly.

The only time this has happened to me, and the solution I found, was not to have the type converter source in the same project as whatever code was actually using it, and to use that as a binary reference, not just shift it to another project referenced in source form. Sorry I can't really help, what I posted above is what I experienced when I was experimenting with type converters. I haven't really used them since, as I tend to either use pre-built converters or designers.