TypeConverters 和 XAMLTypeConverters and XAML

本主题介绍将从字符串进行的类型转换作为常规 XAML 语言功能的用途。This topic introduces the purpose of type conversion from string as a general XAML language feature. 在 .NET Framework 中,TypeConverter 类作为托管自定义类的实现的一部分提供特定用途,该托管自定义类可用作 XAML 特性用法中的属性值。In the .NET Framework, the TypeConverter class serves a particular purpose as part of the implementation for a managed custom class that can be used as a property value in XAML attribute usage. 如果你编写自定义类,并且你希望类的实例可以用作 XAML 可设置属性值,则可能需要将 TypeConverterAttribute 应用到类、编写自定义 TypeConverter 类或同时使用这两种方法。If you write a custom class, and you want instances of your class to be usable as XAML settable attribute values, you might need to apply a TypeConverterAttribute to your class, write a custom TypeConverter class, or both.

类型转换概念Type Conversion Concepts

XAML 和字符串值XAML and String Values

在 XAML 文件中设置特性值时,该值的初始类型是纯文本形式的字符串。When you set an attribute value in a XAML file, the initial type of that value is a string in pure text. 甚至其他基元(如 Double)最初都是文本字符串到 XAML 处理器。Even other primitives such as Double are initially text strings to a XAML processor.

XAML 处理器需要两条信息来处理特性值。A XAML processor needs two pieces of information in order to process an attribute value. 第一条信息是所设置的属性的值类型。The first piece of information is the value type of the property that is being set. 定义特性值以及在 XAML 中进行处理的任何字符串都必须最终转换或解析为该类型的值。Any string that defines an attribute value and that is processed in XAML must ultimately be converted or resolved to a value of that type. 如果值是 XAML 分析器可理解的基元(如数值),则会尝试直接转换字符串。If the value is a primitive that is understood by the XAML parser (such as a numeric value), a direct conversion of the string is attempted. 如果值是枚举,则字符串用于检查是否存在与该枚举中的命名常量匹配的名称。If the value is an enumeration, the string is used to check for a name match to a named constant in that enumeration. 如果值既不是分析器可理解的基元,也不是枚举,则所讨论的类型必须能够基于转换后的字符串提供类型的实例或值。If the value is neither a parser-understood primitive nor an enumeration, then the type in question must be able to provide an instance of the type, or a value, based on a converted string. 可通过指示类型转换器类达到此目的。This is done by indicating a type converter class. 类型转换器实际上是提供其他类的值的帮助器类,可用于的 XAML 方案和 .NET 代码中的代码调用。The type converter is effectively a helper class for providing values of another class, both for the XAML scenario and also potentially for code calls in .NET code.

在 XAML 中使用现有的类型转换行为Using Existing Type Conversion Behavior in XAML

你可能已经在基础应用程序 XAML 中使用了类型转换行为,只是你还不知道,具体取决于你对基础 XAML 概念的熟悉程度。Depending on your familiarity with the underlying XAML concepts, you may already be using type conversion behavior in basic application XAML without realizing it. 例如,WPF 定义了数百个采用类型 Point的值的属性。For instance, WPF defines literally hundreds of properties that take a value of type Point. Point 是描述二维坐标空间中的坐标的值,它实际上只具有两个重要属性: XYA Point is a value that describes a coordinate in a two-dimensional coordinate space, and it really just has two important properties: X and Y. 当您在 XAML 中指定一个点时,可以将其指定为一个字符串,该字符串带有分隔符(通常为逗号),X 和您提供的 Y 值之间。When you specify a point in XAML, you specify it as a string with a delimiter (typically a comma) between the X and Y values you provide. 例如:<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>For example: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>.

甚至此简单类型的 Point 和它在 XAML 中的简单用法都涉及类型转换器。Even this simple type of Point and its simple usage in XAML involve a type converter. 在这种情况下,为类 PointConverterIn this case that is the class PointConverter.

在类级别定义的 Point 的类型转换器可简化采用 Point的所有属性的标记用法。The type converter for Point defined at the class level streamlines the markup usages of all properties that take Point. 如果没有类型转换器,那么对于前面显示的同一示例,将需要更冗长的标记,如下所示:Without a type converter here, you would need the following much more verbose markup for the same example shown previously:

<LinearGradientBrush>
  <LinearGradientBrush.StartPoint>
    <Point X="0" Y="0"/>
  </LinearGradientBrush.StartPoint>
  <LinearGradientBrush.EndPoint>
    <Point X="1" Y="1"/>
  </LinearGradientBrush.EndPoint>
</LinearGradientBrush>

使用类型转换字符串或使用更复杂的等效语法通常是编码风格的选择。Whether to use the type conversion string or a more verbose equivalent syntax is generally a coding style choice. XAML 工具工作流也可能会影响值的设置方式。Your XAML tooling workflow might also influence how values are set. 某些 XAML 工具可能会生成最复杂的标记窗体,以便更容易往返于设计器视图或其自身的序列化机制。Some XAML tools tend to emit the most verbose form of the markup because it is easier to round-trip to designer views or its own serialization mechanism.

通常可以在 WPF 和 .NET Framework 类型上发现现有的类型转换器,方法是检查某个类(或属性)是否存在已应用的 TypeConverterAttributeExisting type converters can generally be discovered on WPF and .NET Framework types by checking a class (or property) for the presence of an applied TypeConverterAttribute. 此属性将对支持类型转换器转换类型的值的类进行命名,用于 XAML 或其他可能的用途。This attribute will name the class that is the supporting type converter for values of that type, for XAML purposes as well as potentially other purposes.

类型转换器和标记扩展Type Converters and Markup Extensions

标记扩展和类型转换器根据 XAML 处理器行为及其应用场景来实现正交角色。Markup extensions and type converters fill orthogonal roles in terms of XAML processor behavior and the scenarios that they are applied to. 尽管上下文可用于标记扩展用途,但通常不会在标记扩展实现中检查属性的类型转换行为(其中标记扩展提供了一个值)。Although context is available for markup extension usages, type conversion behavior of properties where a markup extension provides a value is generally is not checked in the markup extension implementations. 换言之,即使标记扩展返回一个文本字符串作为其 ProvideValue 输出,该字符串上应用于特定属性或属性值类型的类型转换行为也不会被调用。通常,标记扩展的目的是在不调用任何类型转换器的情况下,处理字符串和返回对象。In other words, even if a markup extension returns a text string as its ProvideValue output, type conversion behavior on that string as applied to a specific property or property value type is not invoked, Generally, the purpose of a markup extension is to process a string and return an object without any type converter involved.

需要标记扩展而不是类型转换器的一种常见情况是使对已存在的对象进行引用。One common situation where a markup extension is necessary rather than a type converter is to make a reference to an object that already exists. 无状态类型转换器最多只能生成新实例,这可能并不理想。At best, a stateless type converter could only generate a new instance, which might not be desirable. 若要深入了解标记扩展,请参阅标记扩展和 WPF XAMLFor more information on markup extensions, see Markup Extensions and WPF XAML.

本机类型转换器Native Type Converters

在 XAML 分析器的 WPF 和 .NET XAML 实现中,某些特定类型具有本机类型转换处理,但在传统上可能不会将这些类型视为基元。In the WPF and .NET Framework implementation of the XAML parser, there are certain types that have native type conversion handling, yet are not types that might conventionally be thought of as primitives. 这种类型的一个示例是 DateTimeAn example of such a type is DateTime. 这种情况的原因取决于 .NET Framework 体系结构的工作原理:类型 DateTime 是在 mscorlib 中定义的,这是 .NET 中最基本的库。The reason for this is based on how the .NET Framework architecture works: the type DateTime is defined in mscorlib, the most basic library in .NET. DateTime 不允许使用来自引入依赖关系的另一个程序集的特性进行特性化(TypeConverterAttribute 来自系统),因此不能支持通过特性化进行的正常类型转换器发现机制。DateTime is not permitted to be attributed with an attribute that comes from another assembly that introduces a dependency (TypeConverterAttribute is from System) so the usual type converter discovery mechanism by attributing cannot be supported. 相反,XAML 分析器具有需要此类本机处理的类型的列表,它可通过与真正基元的处理方式类似的方式来处理这些类型。Instead, the XAML parser has a list of types that need such native processing and processes these similarly to how the true primitives are processed. (如果 DateTime 这涉及调用 Parse。)(In the case of DateTime this involves a call to Parse.)

实现类型转换器Implementing a Type Converter

TypeConverterTypeConverter

在前面给出的 Point 示例中,提到了类 PointConverterIn the Point example given previously, the class PointConverter was mentioned. 对于 XAML 的 .NET 实现,用于 XAML 用途的所有类型转换器都是从基类派生的类 TypeConverterFor .NET implementations of XAML, all type converters that are used for XAML purposes are classes that derive from the base class TypeConverter. TypeConverter 类存在于 XAML 存在之前的 .NET Framework 版本中:其原始用法之一是在可视化设计器中为属性对话框提供字符串转换。The TypeConverter class existed in versions of .NET Framework that precede the existence of XAML; one of its original usages was to provide string conversion for property dialogs in visual designers. 对于 XAML,将扩展 TypeConverter 的角色,以使其包含允许分析字符串属性值并将特定对象属性的运行时值作为属性进行序列化的字符串转换的基类和字符串转换。For XAML, the role of TypeConverter is expanded to include being the base class for to-string and from-string conversions that enable parsing a string attribute value, and possibly processing a run-time value of a particular object property back into a string for serialization as an attribute.

TypeConverter 定义了四个成员,它们与字符串之间的相互转换相关,用于 XAML 处理目的:TypeConverter defines four members that are relevant for converting to and from strings for XAML processing purposes:

其中,最重要的方法是 ConvertFromOf these, the most important method is ConvertFrom. 此方法将输入字符串转换为所需的对象类型。This method converts the input string to the required object type. 严格地说,可以实现 ConvertFrom 方法,以将范围更广泛的类型转换为转换器的预期目标类型,从而为超出 XAML (如支持运行时转换)的目的提供支持,但对于 XAML 而言,这只是可以处理 String 输入的代码路径。Strictly speaking, the ConvertFrom method could be implemented to convert a much wider range of types into the converter's intended destination type, and thus serve purposes that extend beyond XAML such as supporting run-time conversions, but for XAML purposes it is only the code path that can process a String input that matters.

下一个最重要的方法是 ConvertToThe next most important method is ConvertTo. 如果将应用程序转换为标记表示形式(例如,如果它作为文件保存到 XAML),ConvertTo 负责生成标记表示形式。If an application is converted to a markup representation (for instance, if it is saved to XAML as a file), ConvertTo is responsible for producing a markup representation. 在这种情况下,对 XAML 重要的代码路径是传递 StringdestinationTypeIn this case, the code path that matters for XAML is when you pass a destinationType of String .

CanConvertToCanConvertFrom 是在服务查询 TypeConverter 实现的功能时使用的支持方法。CanConvertTo and CanConvertFrom are support methods that are used when a service queries the capabilities of the TypeConverter implementation. 必须实现这些方法以便为转换器的等效转换方法支持的特定于类型的情况返回 trueYou must implement these methods to return true for type-specific cases that the equivalent conversion methods of your converter support. 对于 XAML 用途,这通常意味着 String 类型。For XAML purposes, this generally means the String type.

XAML 的区域性信息和类型转换器Culture Information and Type Converters for XAML

每个 TypeConverter 实现都可以对构成转换的有效字符串的内容进行自己的解释,还可以使用或忽略作为参数传递的类型说明。Each TypeConverter implementation can have its own interpretation of what constitutes a valid string for a conversion, and can also use or ignore the type description passed as parameters. 对于区域性和 XAML 类型转换,有一个重要的注意事项。There is an important consideration with regard to culture and XAML type conversion. XAML 完全支持使用可本地化的字符串作为特性值。Using localizable strings as attribute values is entirely supported by XAML. 但不支持将该可本地化字符串用作具有特定区域性要求的类型转换器输入,因为 XAML 特性值的类型转换器包含一个必要的固定语言分析行为,该行为使用 en-US 区域性。But using that localizable string as type converter input with specific culture requirements is not supported, because type converters for XAML attribute values involve a necessarily fixed-language parsing behavior, using en-US culture. 有关此限制的设计原因的详细信息,请参阅 XAML 语言规范([的]For more information on the design reasons for this restriction, you should consult the XAML language specification ([MS-XAML].

区域性可能会产生问题的示例之一是,某些区域性使用逗号作为数字的小数点分隔符。As an example where culture can be an issue, some cultures use a comma as their decimal point delimiter for numbers. 这将与许多 WPF XAML 类型转换器所具有的使用逗号作为分隔符的行为发生冲突(根据常用的 X,Y 形式等过去的先例,或逗号分隔的列表)。This will collide with the behavior that many of the WPF XAML type converters have, which is to use a comma as a delimiter (based on historical precedents such as the common X,Y form, or comma delimited lists). 即使在周围的 XAML 中传递区域性(将 Languagexml:lang 设置为 sl-SI 区域性,以此方式使用逗号作为小数点的区域性的一个示例)也不能解决此问题。Even passing a culture in the surrounding XAML (setting Language or xml:lang to the sl-SI culture, an example of a culture that uses a comma for decimal in this way) does not solve the issue.

实现 ConvertFromImplementing ConvertFrom

若要能够用作支持 XAML 的 TypeConverter 实现,该转换器的 ConvertFrom 方法必须接受字符串作为 value 参数。To be usable as a TypeConverter implementation that supports XAML, the ConvertFrom method for that converter must accept a string as the value parameter. 如果字符串采用有效格式,并且可以由 TypeConverter 实现进行转换,则返回的对象必须支持强制转换为属性所需的类型。If the string was 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. 否则, ConvertFrom 实现必须返回 nullOtherwise, the ConvertFrom implementation must return null.

每个 TypeConverter 实现都可以对构成转换的有效字符串的内容进行自己的解释,还可以使用或忽略作为参数传递的类型说明或区域性上下文。Each TypeConverter implementation can have its own interpretation of what constitutes a valid string for a conversion, and can also use or ignore the type description or culture contexts passed as parameters. 但是,WPF XAML 处理可能不会在所有情况下都将值传递给类型说明上下文,还可能不会基于 xml:lang 传递区域性。However, the WPF XAML processing might not pass values to the type description context in all cases, and also might not pass culture based on xml:lang.

备注

请勿使用大括号字符(尤其是 {)作为字符串格式的可能元素。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.

实现 ConvertToImplementing ConvertTo

ConvertTo 可能用于序列化支持。ConvertTo is potentially used for serialization support. 通过 ConvertTo 为自定义类型及其类型转换器实现的序列化支持不是绝对要求。Serialization support through ConvertTo for your custom type and its type converter is not an absolute requirement. 但是,如果要实现控件,或使用序列化作为类的功能或设计的一部分,则应实现 ConvertToHowever, if you are implementing a control, or using serialization of as part of the features or design of your class, you should implement ConvertTo.

若要用作支持 XAML 的 TypeConverter 实现,该转换器的 ConvertTo 方法必须接受作为 value 参数支持的类型(或值)的实例。To be usable as a TypeConverter implementation that supports XAML, the ConvertTo method for that converter must accept an instance of the type (or a value) being supported as the value parameter. 如果 destinationType 参数是类型 String,则返回的对象必须能够强制转换为 StringWhen the destinationType parameter is the type String, then the returned object must be able to be cast as String. 返回字符串必须表示 value 的序列化值。The returned string must represent a serialized value of value. 理想情况下,如果您选择的序列化格式应能够生成相同的值,则 ConvertFrom 它应能够生成相同的值,而不会产生大量信息丢失。Ideally, the serialization format you choose should be capable of generating the same value if that string were passed to the ConvertFrom implementation of the same converter, without significant loss of information.

如果值无法进行序列化,或转换器不支持序列化,则 ConvertTo 实现必须返回 null,并且在此情况下允许引发异常。If the value cannot be serialized, or the converter does not support serialization, the ConvertTo implementation must return null, and is permitted to throw an exception in this case. 但是,如果确实引发了异常,则应报告无法使用该转换作为 CanConvertTo 实现的一部分,以便支持首先检查 CanConvertTo 以避免异常的最佳做法。But if you do throw exceptions, you should report the inability to use that conversion as part of your CanConvertTo implementation so that the best practice of checking with CanConvertTo first to avoid exceptions is supported.

如果 destinationType 参数不是 String类型,则可以选择自己的转换器处理。If destinationType parameter is not of type String, you can choose your own converter handling. 通常情况下,会恢复为基实现处理,在方法 ConvertTo 引发特定异常。Typically, you would revert to base implementation handling, which in the basemost ConvertTo raises a specific exception.

实现 CanConvertToImplementing CanConvertTo

对于 CanConvertTo 类型的 truedestinationType 实现应返回 String,否则遵从基实现。Your CanConvertTo implementation should return true for destinationType of type String, and otherwise defer to the base implementation.

实现 CanConvertFromImplementing CanConvertFrom

对于 CanConvertFrom 类型的 truesourceType 实现应返回 String,否则遵从基实现。Your CanConvertFrom implementation should return true for sourceType of type String, and otherwise defer to the base implementation.

应用 TypeConverterAttributeApplying the TypeConverterAttribute

为了使您的自定义类型转换器被 XAML 处理器用作自定义类的操作类型转换器,必须将 TypeConverterAttribute 应用到您的类定义。In order for your custom type converter to be used as the acting type converter for a custom class by a XAML processor, you must apply the TypeConverterAttribute to your class definition. 通过特性指定的 ConverterTypeName 必须是自定义类型转换器的类型名。The ConverterTypeName that you specify through the attribute must be the type name of your custom type converter. 应用此特性后,当 XAML 处理器处理属性类型使用自定义类类型的值时,它可以输入字符串并返回对象实例。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 also provide a type converter on a per-property basis. 不要将 TypeConverterAttribute 应用到类定义,而是将其应用于属性定义(主定义,而不是 get/set 实现中)。Instead of applying a TypeConverterAttribute to the class definition, apply it to a property definition (the main definition, not the get/set implementations within it). 属性的类型必须与自定义类型转换器处理的类型匹配。The type of the property must match the type that is processed by your custom type converter. 应用此特性时,当 XAML 处理器处理该属性的值时,它可以处理输入字符串并返回对象实例。With this attribute applied, when a XAML processor handles values of that property, it can process input strings and return object instances. 如果选择使用 Microsoft .NET 框架中的属性类型或不能控制类定义并且无法应用 TypeConverterAttribute 的其他库,则每属性类型转换器方法特别有用。The per-property type converter technique is particularly useful if you choose to use a property type from Microsoft .NET Framework or from some other library where you cannot control the class definition and cannot apply a TypeConverterAttribute there.

另请参阅See also