Поделиться через


TypeConverters and XAML

Microsoft Silverlight will reach end of support after October 2021. Learn more.

The TypeConverter class serves a particular purpose as part of the Silverlight implementation of XAML. Type converters process the XAML attribute values and convert attribute strings to object values when a XAML processor creates the runtime object representation. If you write a custom class, and you want instances of your class to be settable through XAML attribute values, you generally must write a custom TypeConverter class, and then apply a TypeConverterAttribute to your classes or properties that reference your type converter implementation.

This topic contains the following sections:

  • XAML and Type Conversion of String Values

  • Implementing a Type Converter

  • Context and Culture in a XAML TypeConverter

  • Applying the TypeConverterAttribute

  • Best Practices for TypeConverter Implementations

XAML and Type Conversion of String Values

When you set an attribute value in XAML, the initial type of that value is String. Even other primitives such as Double are initially strings to a XAML processor. The conversion to other non-string primitive values or to values of named members of an enumeration is relatively straightforward because of native type conversion features that are built into the Silverlight XAML processor. TypeConverter is relevant for the remaining cases where the Silverlight core classes, library classes or any code built on Silverlight wants to support a way to specify a new object value in XAML by providing an attribute value for an associated property.

A XAML processor needs two pieces of information in order to process an attribute value. The first piece of information is the type of the property value that is being set. Any string that is given as an attribute value in XAML must ultimately be converted or resolved to a value that is the property's type. If the property type is a primitive, a direct conversion of the string is attempted. If the property type is an enumeration, the string is used to check for a member in that enumeration. If the property type is neither a primitive or an enumeration, then the conversion behavior of the property or type in question must be able to provide an instance of the type, or a value, based on converting the provided attribute value string.

In some cases the type conversion is native to the Silverlight XAML processor. An example of this type conversion case is values of type Point. Type conversion for Point is native to the Silverlight XAML parsing behavior and is not CLR attributed. In other cases, Silverlight implements a TypeConverter class, then attributes types or members to use it. An example of this type conversion case is values of type Nullable<bool>.

The TypeConverter Class

If the value is not a primitive type or enumeration, there is no native conversion, and there is no markup extension usage, then there must be some means of converting a String to the appropriate value or a new instance when the XAML is processed. This is the role of the TypeConverter class.

NoteNote:

TypeConverter as a class can have other usages besides XAML; in the .NET Framework, TypeConverter existed as a class long before XAML existed. The Silverlight and WPF XAML processors and general XAML design both use the TypeConverter pattern for attribute value conversion because it is an existing coding pattern that fulfilled the conversion requirements when the type conversion involves a string source.

The Silverlight implementation of TypeConverter defines two members that are relevant for converting to and from strings for XAML processing purposes:

Of these, the most important method is ConvertFrom(ITypeDescriptorContext, CultureInfo, Object). This method converts the input string to the required object type.

CanConvertFrom(ITypeDescriptorContext, Type) is a support method that can be used when a service queries the capabilities of the TypeConverter implementation. You must implement CanConvertFrom(ITypeDescriptorContext, Type) to return true for certain cases, particularly for the String type.

Implement the signatures that take ITypeDescriptorContext, rather than the signatures that do not take ITypeDescriptorContext. This implementation pattern is consistent with the WPF and general .NET Framework pattern for implementing a TypeConverter, and these are the signatures that the XAML processor will call, although it may do so passing fixed values for ITypeDescriptorContext or CultureInfo in some cases. For the non-ITypeDescriptorContext signatures, your implementation should call the base implementation.

Silverlight 5 does not use ConvertTo (and CanConvertTo) because it does not incorporate a native serialization that uses a type converter for serializing from XAML. You should still consider implementing ConvertTo (and CanConvertTo) as a best practice for completing the wider interoperation functionality of your converter class.

Implementing a Type Converter

The following sections describe each of the four virtual methods you must override to implement a type converter for Silverlight XAML.

Implementing ConvertFrom

To be usable as a TypeConverter implementation that supports XAML, the ConvertFrom(ITypeDescriptorContext, CultureInfo, Object) method for that converter must accept a string as the value parameter. If the string is in valid format, and can be converted by the TypeConverter implementation, then the returned object must support a cast to the type expected by the property. Otherwise, the ConvertFrom(ITypeDescriptorContext, CultureInfo, Object) implementation must return null.

Each TypeConverter implementation can have its own interpretation of what constitutes a valid string for a conversion.

NoteNote:

Do not use the curly brace characters, particularly {, as a possible element of your string format. These characters are reserved as the entry and exit for a markup extension sequence.

Implementing CanConvertFrom

Your CanConvertFrom(ITypeDescriptorContext, Type) implementation should return true for sourceType of type String, and otherwise defer to the base implementation.

Implementing CanConvertTo and ConvertTo

As stated previously in the "TypeConverter Class" section, Silverlight does not provide XAML serialization exposure and does not call save-path type conversion behavior itself. Thus, for Silverlight purposes, all you typically do for a dedicated Silverlight type converter is use the Visual Studio generated implementation override wrappers that call base. This would result in conversion exceptions if they are ever called, but Silverlight code would not attempt to call those methods. However, you might consider providing an implementation in order to make your type converter more robust, such as for non-XAML usages.

Context and Culture in a XAML TypeConverter

Do not rely on information in context, it may be null. Do not throw if context or culture is null. If input values for context or culture are null, then you should call base, passing the null context. This behavior gives a more consistent exception.

culture when called by the Silverlight XAML parser is always the en-us culture, so you can assume that behavior if you are writing a TypeConverter that supports XAML parsing. The reasons for this behavior are explained in the topic Creating Globally Aware Applications.

Culture behavior becomes particularly relevant for processing delimiters in a string syntax. For example, a comma under en-us culture cannot clash with the decimal-separator usage assigned to a comma character under some cultures. For more information, see the "Best Practices for TypeConverter Implementations" section of this topic

Support for other culture values might be useful if you intend to support type conversion for scenarios other than XAML support.

Applying the TypeConverterAttribute

In order for your custom type converter to be used as the acting type converter for a custom class, you must apply the TypeConverterAttribute to your class definition. The ConverterTypeName that you specify through the attribute must be the type name of your custom type converter. With this attribute applied, when a XAML processor handles values where the property type uses your custom class type, it can input strings and return object instances. You can apply TypeConverterAttribute to an interface, although this is less common and is not done by any Silverlight-implemented interfaces.

You can also provide a type converter on a per-property basis. Instead of applying a TypeConverterAttribute to the class definition, apply it to a property definition (the main definition, not the get/set accessor implementations within it). The type of the property must match the type that is processed by your custom type converter. With this attribute applied, when a XAML processor handles values of that property, it can process input strings and return object instances. The per-property type converter technique is particularly useful if you choose to use a property type where you cannot control the class definition and cannot apply a TypeConverterAttribute to the class.

TypeConverterAttribute and Derived Classes

If you apply a TypeConverterAttribute to a class, then derive from that class and use the derived class type as the specific property type, TypeConverterAttribute behavior does not inherit. You must reapply another TypeConverterAttribute to the derived class definition or change the property type to be the base type. The XAML parser looks for exact type matches of property type to declaring type when determining if a type converter is available for a value. By normal rules of CLR inheritance you could have provide derived classes or base classes for the actual value.

When TypeConverterAttribute is applied to individual properties as opposed to their destination types, the property preserves the conversion behavior even if the property-owning type is derived from, so long as the original property is not shadowed.

Best Practices for TypeConverter Implementations

Typically, you implement a TypeConverter for XAML in order to promote a streamlined attribute usage for one or more properties. You might do this for properties where most of the other commonly-used properties already support an attribute syntax, and requiring a property element syntax for your new property would result in overly verbose markup.

You should consider that when you define a TypeConverter, you are defining a self-contained grammar. It is important to keep your grammar fairly simple, and to use grammar conventions that might be known or intuitive to your users. If properly attributed, type conversion can be invoked from the Properties window if you are editing XAML with Visual Studio. This helps guide users to discover your usage, and Visual Studio will reject invalid input for a type-converter enabled property as a property-editing feature. Some Visual Studio property scenarios (such as the color picker) also support specialized property editors that parallel the type converter grammar possibilities. However, other design environments that produce or edit XAML do not necessarily have any hinting available that can help users discover your type-conversion grammar. Other design environments do not necessarily reject invalid XAML before attempting to load that XAML at run time, and the run time XAML parser errors are not always helpful for indicating how a type converter usage might be invalid.

Examples of an appropriate type conversion scenario include cases where pre-existing conventions for expressing that data exist in other markup paradigms, or conventions for how that data is expressed in the written word. For example, the X,Y format for type conversion of a Point, using a comma as delimiter between X and Y, is based on presentation conventions that existed in mathematics. Another example scenario is if your property generally supports a main data type, but also supports certain special values that cannot be expressed in the main data type's string representations. An example of this type conversion scenario is Duration, which generally supports TimeSpan values (which have their own type converter for the time format), but also supports special values such as the literal string Forever. For this scenario, a best practice is to expose a static field or property on the converted type. This provides an equivalent value for code usages without requiring code users to create and invoke your type converter, passing the string token literal. If permitted by CLR rules, the field or property should have the same name as the literal that you use as the special grammar information item.

Typically, a type conversion grammar contains more than one information item. A comma is a typical choice as a separator between atoms of a string that a type converter splits and processes as parts. A space character is also often used as a separator, and many type converter implementations treat a comma or space as equivalent for separator use.

Whenever possible, apply TypeConverterAttribute to types, rather than properties, if you define the type. You should reserve TypeConverterAttribute on properties for the following cases:

  • You do not define the property destination type, but want to repurpose that destination type for use by your property's XAML usage.

  • A common type is used on more than one property, but each such property has different validation rules for which of the type's values can be supported as a value.

  • You define the type, but do not want that type to take a dependency on the Silverlight assemblies that are needed for TypeConverterAttribute or for CLR attributing overall.

Do not attempt to use the opening curly brace ({) as a significant character for a type conversion grammar. This will clash with how a XAML parser identifies a markup extension usage.

See Also

Reference

Concepts