Custom Controls Design Time Support Part 5: Custom TypeConverters

In the previous post I gave an introduction on common TypeConverters and how to use them, in this post I will show you how to implement custom TypeConverters for your own custom data types.

First, lets explore the TypeConverter base type virtual methods …

Method Description
CanConvertFrom Returns a Boolean value indicating whether the converter can convert an object of the specified type to the type that this converter represents.
CanConvertTo Returns a Boolean value indicating whether the converter can convert an object to the specified type.
ConvertFrom Converts the specified value to the type represented by this converter.
ConvertFromInvariantString Converts the string representation of a value to a type that this converter represents, using the invariant culture, which is English.
ConvertFromString Converts the string representation of a value to a type that this converter represents, using the given culture.
ConvertTo Converts the given object to the specified type.
ConvertToInvariantString Converts the given object to a string, using the invariant culture.
ConvertToString Converts the given object to a string, using the specified culture.
CreateInstance Creates or recreates an object given a dictionary of property values. The dictionary contains property name-value pairs.
GetCreateInstanceSupported Returns a Boolean value indicating whether CreateInstance has been implemented.
GetProperties Returns a collection of PropertyDescriptor objects for the given object.
GetPropertiesSupported Returns a Boolean value indicating whether the given object supports properties.
GetStandardValues Returns a collection of standard values for the type that this converter represents.
GetStandardValuesExclusive Returns a Boolean value indicating whether the standard values are mutually exclusive.
GetStandardValuesSupported Returns a Boolean value indicating whether GetStandardValues is implemented.
IsValid Returns a Boolean value indicating whether the specified value is valid for the type that this converter represents.

[more] 

Now lets implement a simple one, considering a type Point3D which simply has 3 int properties representing a point in the 3D (x,y,z).

[code:c#]

public struct Point3D
{
    private int _x;
    private int _y;
    private int _z;

    public int X { get { return _x; } set { _x = value; } }
    public int Y { get { return _y; } set { _y = value; } }
    public int Z { get { return _z; } set { _z = value; } }
}

[/code]

When adding a Point3D property to our testing ButtonEx Control the Point would look like this in the PropertyWindow

[code:c#]

public class Point3DConverter : TypeConverter
{
   public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
   {
   if (sourceType == typeof(string))
      return true;
   else
      return base.CanConvertFrom(context, sourceType);
   }

   public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
   {
      if (destinationType == typeof(Point3D))
         return true;
      else
         return base.CanConvertTo(context, destinationType);
   }

   public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object src, Type destinationType)
   {
       //convert to a string
       if (destinationType == typeof(string))
      {
         Point3D p3 = (Point3D)src;
         string result = p3.X + "," + p3.Y + "," + p3.Z;
         return result;
       }
       return base.ConvertTo(context, culture, src, destinationType);
  }
   public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object src) {
  {
      //convert from a string
      if (src is string)
     {
         Point3D p3 = new Point3D();
         string[] temp = ((string)src).Split(',');
         p3.X = int.Parse(temp[0]);
         p3.Y = int.Parse(temp[1]);
         p3.Z = int.Parse(temp[2]);
        return p3;
       }
     return base.ConvertFrom(context, culture, src);
   }
}

[/code]

Now apply the Point3DConverter to the Point3D struct, so anytime the Point3D is used then the Point3DConverter is used by default as when you use the Size type it is always associated with the SizeConverter, same to FontConverter used default with Font type.

[code:c#]

[TypeConverter(typeof(Point3DConverter))]
public struct Point3D

[/code]

After applying the Converter the property would look like this:

 

This would be enough to use the Point3D smoothly in the desing time, but we can make it more fancy by overriding GetPropertiesSupported and GetProperties methods.

[code:c#]

public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
   return true;
}

public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object src, Attribute[] attributes)
{
   return TypeDescriptor.GetProperties(src, attributes);
}

[/code]

Now it will be expanded in the PropertyWindow

 

To show how the GetStandardValuesSupported and GetStandardValues work take a look on the following properties.

As you are expecting the values appearing in the drop down list are the StandardValues, accordingly the EnumConverter overrides those two methods in order to return the values of the Enum.

Next part I will show how to use the StandardValues and the rest of the methods.

Point3D.cs (2.58 kb)

One thought on “Custom Controls Design Time Support Part 5: Custom TypeConverters”

  1. I’ve used TypeConverters for various reasons before, but I didn’t realize all the power they possess until now. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *