I have one class derived from TypeConverter and I apply it to different properties to show different values drop down list. How can I define which properties from ExClassConverter: TypeConverter to fill drop down list with appropriate values? TypeConverter.GetStandardValues Method (ITypeDescriptorContext).NET Framework 1.1 Returns a collection of standard values for the data type this type converter is.
30 Jul 2013CPOL
This follow up article expands upon the sample in the first part, to include more concise design time code generation, expandable property support, and finally custom lists of values.
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:These 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.
Lets update
ConvertTo
to include the extract support.We still do our
null
check to ensure we have a valid value to convert, but now we check to see if the type is either string
or InstanceDescriptor
and process accordingly.For instance descriptors, we use Reflection in order to get the constructor which takes two parameters, and then we create an
InstanceDescriptor
object from that. Easy enough!Now when we modify our
SampleClass
component in the designer, source code is generated similar to the below. (With the caveat of the warning in the next section)Note that I'd also modified the properties on the
SampleClass
to include [DefaultValue(typeof(Length), ')]
for default value support.Much cleaner!
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:An awkward example, but it does demonstrate the feature.
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 generated 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 an easy task, and is something that can help enrich editing functionality.
You can download the complete example from the link at the top of this article.
-->Definition
Returns a collection of standard values for the data type this type converter is designed for.
Overloads
GetStandardValues() | Returns a collection of standard values from the default context for the data type this type converter is designed for. |
GetStandardValues(ITypeDescriptorContext) | Returns a collection of standard values for the data type this type converter is designed for when provided with a format context. |
Returns a collection of standard values from the default context for the data type this type converter is designed for.
Returns
A TypeConverter.StandardValuesCollection containing a standard set of valid values, or
null
if the data type does not support a standard set of values.Remarks
As implemented in this class, this method always returns
null
.Returns a collection of standard values for the data type this type converter is designed for when provided with a format context.
Parameters
- context
- ITypeDescriptorContext
An ITypeDescriptorContext that provides a format context that can be used to extract additional information about the environment from which this converter is invoked. This parameter or properties of this parameter can be
null
.Returns
A TypeConverter.StandardValuesCollection that holds a standard set of valid values, or
null
if the data type does not support a standard set of values.Examples
For an example on this function, see the TypeConverter class.
Remarks
As implemented in TypeConverter, this method always returns
null
.Notes to Inheritors
Override this method if the type you want to convert supports standard values.