Monday, October 24, 2005

TypeConverters

Recently, Chuck Jazdzewski posted an article about XAML and Type Converters. A while back, Joe Stegman wrote an article entitled "Using the Windows Forms XML Parser Sample". Both of these articles talk about and use TypeConverters outside of the Windows Forms design time experience.

I thought it'd be interesting to talk about what TypeConverters are in the more generic sense.

What is a TypeConverter?
According to MSDN TypeConverter Class documentation, the TypeConverter class:

    Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties
    To provide a little more context, some of the key methods of the TypeConverter class include CanConvertFrom(), CanConvertTo(), ConvertFrom, and ConvertTo(). As you can see, it provides a means to convert from one type to another.

    Typically, TypeConverters are discussed in the context of Windows Forms.
    1. Converting strings typed into the Windows Forms property browser/grid to the type that the property being set requires. (typing in Red and getting the System.Drawing.Color.Red instance)
    2. Converting a type to an InstanceDescriptor so that the Windows Forms code serialization mechanism has additional information about how to generate the serialization and instantiation code for that type.
    3. Converting to and from strings when a type is serialized to a resx file
    The key functionality behind TypeConverters is that the TypeConverterAttribute is used to bind a class or property with a TypeConverter and that TypeConverter instance can be retrieved dynamically at runtime.

    For example: Suppose you want to set a property with an incoming value. If the type of the property and the type being passed in match, its simple, you simply set the property. What about if the incoming type is different from the type of the property? You could convert it, but how would you do that in a generic way for any property and incoming type?

    With TypeConverters, you can write generic code that grabs the TypeConverter that is bound to the property you are setting and use it to convert that incoming type to the type the property needs. Of course, the TypeConverter instance needs to support the conversion, and it provides the CanConvertTo() and CanConvertFrom() methods to check that before actually attempting the conversion.

    In the two articles mentioned above, TypeConverters are used to change string representations to instances of types.

    In one article its in the context of XAML, where the TypeConverter bound to a class is used to create an instance of that class from a string.

    In the other article, its in the context of Windows Forms markup language (XML to describe a Windows Forms UI) where the TypeConverter bound to a property is used to set that property from a string.

    MSDN also shows how to do parameter checking for a property that takes an enum however I feel using the Enum.IsDefined() method is a better way to handle that.

    Finally, you can also get "standard values" for a given type from a TypeConverter, for example the static instances of the Color struct (Color.Red, Color.AliceBlue etc.).

    Getting a TypeConverter
    As mentioned before, you can get a TypeConverter that is bound to a class or a property. In both cases, you want to go through a TypeDescriptor.

    For a class:

    Color c = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromString("Red");
    This example shows how to get the TypeConverter for a property and also how you can set a value from any type on that property:

    The "obj" and "propName" arguments specify the instance and the property to set while the "val" argument specifies the new value for that property.
    public static void SetProperty(object obj, string propName, object val)
    {
    PropertyDescriptor prop = TypeDescriptor.GetProperties(obj.GetType())[propName];
    if (null != prop)
    {
    // Check for string type
    if (prop.PropertyType.IsAssignableFrom(val.GetType()))
    {
    // Just set the value
    prop.SetValue(obj, val);
    }
    else
    {
    // Need to do type conversion - use a type converter
    TypeConverter tc = TypeDescriptor.GetConverter(prop.PropertyType);
    object newVal = null;

    if ((null != tc) && (tc.CanConvertFrom(val.GetType())))
    {
    newVal = tc.ConvertFrom(val);
    if (null != newVal)
    {
    // Conversion worked, set value
    prop.SetValue(obj, newVal);
    }
    }
    else
    {
    string errMsg = string.Format("Cannot set property {0} on object {1} with value {2}",
    propName, obj, val);
    throw new ArgumentException(errMsg);
    }
    }
    }
    }
    Finally
    Although the majority of the interaction with TypeConverters is done in the context of the Windows Form design time, the mechanism itself is generic and powerful and can be leveraged in a number of other scenarios.

    Some other good articles on TypeConverters to look at:

    Why doesn't my TypeConverter get called?
    Introduction to the TypeConverter
    Whidbey TypeConverter Documentation

    0 Comments:

    Post a Comment

    << Home