Skip to content

Value Converters

Gary edited this page Mar 10, 2015 · 2 revisions

Table of Contents

A value converter converts a property value between its internal data representation in a value editor and a form that appears in a value editing control.

For instance, a value converter for an integer value in a value editor would convert back and forth between an int value and a string representation of the integer that can be displayed in a value editing control. A color converter could convert color stored as an ARGB int value to or from color or string types.

Similarly to a value editor, a value converter is specified in the property descriptor with the Converter property. A given value editor usually has an associated value converter. The value converter must also work for the value editing control the value editor uses.

TypeConverter Class

The System.ComponentModel.TypeConverter class provides a unified way of converting types of values to other types. ATF value converters derive from TypeConverter. TypeConverter contains a large variety of methods, but it is not necessary to implement all of them in a value converter. The most useful methods indicate whether a conversion is possible to or from a given type in a given context — and perform such a conversion.

The System.ComponentModel.TypeDescriptor class provides information about the characteristics for a component, such as its attributes, properties, and events. This class provides the GetConverter() class method to get a TypeConverter for a given object. This TypeConverter may be useful for some converters, as shown for IntColorConverter in one of the examples in Writing a Value Converter below.

Defining Converters for Property Descriptors

Converters can be defined in a property descriptor by constructors or XML Schema annotations.

Property Descriptor Constructors

Property descriptors can be created with constructors, as described in Constructing Property Descriptors.

For example, the ATF DOM Tree Editor Sample defines a property descriptor with the value editor NumericTupleEditor and the value converter FloatArrayConverter in SchemaLoader.cs:

UISchema.UIControlType.Type.SetTag(
    new PropertyDescriptorCollection(
        new PropertyDescriptor[]
    {
        new ChildAttributePropertyDescriptor(
            Localizer.Localize("Translation"),
            UISchema.UITransformType.TranslateAttribute,
            UISchema.UIControlType.TransformChild,
            null,
            Localizer.Localize("Item position"),
            false,
            new NumericTupleEditor(typeof(float), new string[] { "X", "Y", "Z" }),
            new FloatArrayConverter()),
            ...

XML Schema Annotations

Property descriptors can also be created from XML Schema annotations, as described in Creating Property Descriptors with XML Schema Annotations.

For instance, the ATF Timeline Editor Sample specifies the color converter IntColorConverter for the color editor ColorEditor in an annotation defining a property descriptor in timeline.xsd:

<scea.dom.editors.attribute name="color" displayName="Color" description="Display Color"
  editor="Sce.Atf.Controls.PropertyEditing.ColorEditor,Atf.Gui"
  converter="Sce.Atf.Controls.PropertyEditing.IntColorConverter" />

IAnnotatedParams Interface

Value converters, like value editors, can have parameters specified in annotations in an XML Schema.

If a value converter can have parameters in an XML Schema annotation, the value editor must implement IAnnotatedParams. This interface gets the parameters from the schema annotation and initializes the value converter for those parameters.

For example, BoundedIntConverter, which does conversion for the BoundedIntEditor value editor, can have parameters specifying the minimum and maximum values the converter handles. BoundedIntConverter implements IAnnotatedParams:Initialize() to obtain these limits and set its m_min and m_max fields:

public void Initialize( string[] parameters )
{
    if (parameters.Length < 2)
        throw new ArgumentException("Can't parse bounds");

    try
    {
        if (parameters[0].Length > 0)
            m_min = Int32.Parse(parameters[0]);
        if (parameters[1].Length > 0)
            m_max = Int32.Parse(parameters[1]);
    }
    catch
    {
        throw new ArgumentException("Can't parse bounds");
    }

    if (m_min.HasValue && m_max.HasValue && m_min.Value >= m_max.Value)
        throw new ArgumentException("Max must be > min");
}

For a description of how value editors use the IAnnotatedParams interface, see IAnnotatedParams Interface.

ATF Value Converters

This table describes value converters associated with value editors.

Value Editor Class Value Converter Class Implements
IAnnotatedParams
Description
BoundedFloatEditor BoundedFloatConverter Yes Convert float values to a specified range. First argument, if not empty, is the minimum; second, if not empty, is the maximum.
BoundedIntEditor BoundedIntConverter Yes Convert parsed int values to a specified range. First argument, if not empty, is the minimum; second, if not empty, is the maximum.
ColorEditor IntColorConverter No Convert color stored as an ARGB int to or from Color or string types. Used in ATF Timeline Editor Sample.
EnumUITypeEditor EnumTypeConverter
ExclusiveEnumTypeConverter
Yes Value converters for use with enum editors. Convert integers to strings. In ATF property editors. The user can enter any string, even if it doesn't match the list of names. Used in several samples, such as ATF Simple DOM Editor Sample.
FlagsUITypeEditor FlagsTypeConverter Yes Convert int flags to or from a string.
Various FloatArrayConverter No Convert float[] to or from a string of the form "c1,c2,...,cN". Used in ATF DOM Tree Editor Sample.
Various ReadOnlyConverter No Converter for values that are not directly editable by the user. Used in ATF Timeline Editor Sample.
Various UniformFloatArrayConverter No Convert a uniform float[] to or from a string of the form "c1,c2,...,cN". This is useful for uniform scale vectors, for example.

Writing a Value Converter

Consider what parameters the converter needs, based on the value editor it serves. You can provide these parameters in an XML Schema and implement IAnnotatedParams. Or you can provide these parameters in the converter's constructor. You can also do both. For instance, EnumTypeConverter provides several constructors with and without parameters, in addition to implementing IAnnotatedParams:

public EnumTypeConverter();
public EnumTypeConverter(string[] names);
public EnumTypeConverter(string[] names, int[] values);

The first constructor is used when the enumeration data is provided in the XML Schema. Enumeration data can also be passed to the converter in the constructors' parameters.

If the converter implements IAnnotatedParams, implement IAnnotatedParams.Initialize() to get the data from the XML Schema and convert it to the right data type, as shown in IAnnotatedParams Interface.

Implement at least one conversion method in System.ComponentModel.TypeConverter. For example, BoundedFloatConverter implements only this method (in addition to IAnnotatedParams.Initialize()):

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
    float floatValue = (float) base.ConvertFrom(context, culture, value);
    if (m_min.HasValue)
        floatValue = Math.Max(floatValue, m_min.Value);
    if (m_max.HasValue)
        floatValue = Math.Min(floatValue, m_max.Value);
    return floatValue;
}

The method converts the value and then checks it against the bounds. This converter is one way: from a string representing a floating point number to its float value.

By contrast, IntColorConverter implements these methods: CanConvertFrom(), CanConvertTo(), ConvertFrom(), and ConvertTo(). Here is CanConvertTo():

public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
{
    return (destType == typeof(string) ||
            destType == typeof(Color));
}

This particular method is independent of context. Here is the corresponding ConvertTo() method:

public override object ConvertTo(ITypeDescriptorContext context,
        CultureInfo culture,
        object value,
        Type destType)
{
    if (value == null)
        return null;

    if (value is Color)
        value = ((Color)value).ToArgb();

    if (value is int && destType == typeof(string))
    {
        // ARGB int -> string
        Color color = Color.FromArgb((int) value);
        TypeConverter colorConverter = TypeDescriptor.GetConverter(typeof(Color));
        return colorConverter.ConvertTo(context, culture, color, destType);
    }
    else if (value is int && destType == typeof(Color))
    {
        // ARGB int -> Color
        return Color.FromArgb((int) value);
    }

    return base.ConvertTo(context, culture, value, destType);
}

Note that this method calls TypeConverter.GetConverter() to get a converter from an ARGB int to a string, which uses the context. It also calls the base method TypeConverter.ConvertTo() to complete the conversion in some cases.

Topics in this section

Clone this wiki locally