XAML 的类型转换器概述

类型转换器为对象编写器提供逻辑,该对象编写器将 XAML 标记中的字符串转换为对象图中的特定对象。 在 .NET Framework XAML 服务中,类型转换器必须是从 TypeConverter 派生的类。 某些转换器还支持 XAML 保存路径,并且可用于将对象序列化为序列化标记中的字符串形式。 本主题介绍如何以及何时调用 XAML 中的类型转换器,并为 TypeConverter 的方法重写提供实现建议。

本主题包括下列各节。

  • 类型转换概念
  • 实现类型转换器
  • 应用 TypeConverterAttribute
  • 通过标记扩展实现来访问服务提供程序上下文
  • XAML 节点流中的类型转换器
  • 相关主题

类型转换概念

以下各节说明有关 XAML 如何使用字符串以及 .NET Framework XAML 服务中的对象编写器如何使用类型转换器处理在 XAML 源中遇到的某些字符串值的一些基本概念。

XAML 和字符串值

在 XAML 文件中设置特性值时,该值的初始类型通常为字符串,在 XML 中为字符串特性值。 甚至诸如 Double 的其他基元初始也是针对 XAML 处理器的字符串。

在大多数情况下,XAML 处理器需要两条信息才能处理特性值。 第一条信息是要设置的属性的值类型。 用于定义特性值并且在 XAML 中进行处理的任何字符串最终都必须转换或解析为该类型的值。 如果该值为 XAML 分析器能够识别的基元(如数字值),则将尝试直接转换该字符串。 如果特性值引用枚举,则检查提供的字符串,看是否有名称与该枚举中的命名常量匹配。 如果该值既不是分析器所能识别的基元,也不是枚举中的常量名称,则适用的类型必须能够提供基于转换的字符串的值或引用。

注意注意

XAML 语言指令不使用类型转换器。

类型转换器和标记扩展

检查属性类型和其他注意事项之前必须由 XAML 处理器处理标记扩展用法。 例如,如果通常设置为特性的属性具有类型转换,但在特定情况下由标记扩展用法来设置,则首先处理标记扩展行为。 需要标记扩展的一种常见情况是对已经存在的对象进行引用。 对于这种方案,无状态类型转换器只能生成一个新实例,但该实例可能并不是所需的实例。 有关标记扩展的更多信息,请参见XAML 的标记扩展概述

本机类型转换器

在 WPF 和 .NET XAML 服务实现中,有些 CLR 类型具有本机类型转换处理功能,但在传统上可能不会将这些 CLR 类型视为基元。 DateTime 就是这样的一个类型。 这种情况的一个原因在于 .NET Framework 体系结构的工作方式:DateTime 类型在 mscorlib 中进行定义,这是 .NET 中最基础的库。 不允许使用来自引入某种依赖关系的另一个程序集中的特性(TypeConverterAttribute 来自 System)将 DateTime 特性化;因此,不支持通过特性化实现的常规类型转换器发现机制。 而是,XAML 分析器具有需要本机处理的类型的列表,并且它用类似于处理真实基元的方式处理这些类型。 在 DateTime 的情况下,这种处理涉及调用 Parse

实现类型转换器

以下各节讨论 TypeConverter 类的 API。

TypeConverter

使用 .NET Framework XAML 服务时,用于 XAML 的所有类型转换器都是从基类 TypeConverter 派生的类。 TypeConverter 类存在于 XAML 存在之前的 .NET Framework 版本中;原始 TypeConverter 方案之一是为可视化设计器中的属性编辑器提供字符串转换。

对于 XAML,TypeConverter 的作用已扩展。 用于 XAML 时,TypeConverter 是为某些与字符串之间来回转换的功能提供支持的基类。 从字符串转换功能可用于分析 XAML 中的字符串特性值。 转换为字符串功能可用于处理特定对象属性的运行时值,使其恢复为用于序列化的 XAML 特性。

TypeConverter 出于 XAML 处理目的,定义了四个与来回转换字符串相关的成员:

在这些成员中,最重要的方法是 ConvertFrom,此方法将输入的字符串转换为所需的对象类型。 可以将 ConvertFrom 方法实现为将范围更广的类型转换为转换器所需的目标类型。 因此,它的作用范围可以扩展到 XAML 之外,如支持运行时转换。 但是,用于 XAML 时,只有可以处理 String 输入的代码路径是重要的。

第二个最重要的方法是 ConvertTo。 如果将应用程序转换为标记表示形式(例如,如果将其保存为文件形式的 XAML),则 ConvertTo 将用在较大型的 XAML 文本编写器方案中,并生成标记表示形式。 在这种情况下,对 XAML 重要的代码路径是在调用方传递 String 的 destinationType 时。

CanConvertToCanConvertFrom 是当服务查询 TypeConverter 实现的功能时使用的支持方法。 必须实现这些方法才能为转换器的等效转换方法所支持的类型特定情况返回 true。 出于 XAML 目的,这一般表示 String 类型。

区域性信息与 XAML 的类型转换器

每个 TypeConverter 实现可以唯一地解释对一个转换来说何为有效字符串,还可以使用或忽略作为参数传递的类型描述。 区域性和 XAML 类型转换的重要注意事项如下:虽然 XAML 支持将可本地化的字符串用作特性值,但不能将这些可本地化的字符串用作具有特定区域性要求的类型转换器输入。 存在这一限制的原因是,XAML 特性值的类型转换器涉及必要的固定语言 XAML 处理行为,该 XAML 处理行为使用了 en-US 区域性。 有关此限制的设计原因的更多信息,请参见 XAML 语言规范 ([MS-XAML]) 或 WPF 全球化和本地化概述

区域性可能造成问题的一个示例是,某些区域性使用英文逗号而非句点作为字符串形式的数字的小数点分隔符。 此用法与许多现有类型转换器所具有的使用英文逗号作为分隔符的行为发生冲突。 在周围的 XAML 中通过 xml:lang 传递区域性并不能解决该问题。

实现 ConvertFrom

若要使该转换器的 ConvertFrom 方法可用作支持 XAML 的 TypeConverter 实现,该方法必须接受字符串作为 value 参数。 如果该字符串的格式有效,而且可由 TypeConverter 实现进行转换,则返回的对象必须支持强制转换为该属性所预期的类型。 否则,ConvertFrom 实现必须返回 null。

每个 TypeConverter 实现可以唯一地解释组成有效转换字符串的内容,还可以使用或忽略作为参数传递的类型描述或区域性上下文。 但是,WPF XAML 处理可能不会在所有情况下都向类型描述上下文传递值,也有可能不根据 xml:lang 传递区域性。

注意注意

请勿使用大括号 ({}),尤其是左大括号 ({),原因是它是字符串格式的一个元素。这些字符保留为标记扩展序列的入口和出口。

如果类型转换器必须具有从 .NET Framework XAML 服务对象编写器访问 XAML 服务的权限,但针对上下文进行的 GetService 调用不返回该服务,则会引发异常。

实现 ConvertTo

ConvertTo 可潜在用于序列化支持。 通过 ConvertTo 支持对自定义类型及其类型转换器进行序列化不是绝对必需的。 但是,如果您正实现一个控件,或正使用作为类的功能和设计一部分的序列化,则应实现 ConvertTo

若要使该转换器的 ConvertTo 方法可用作支持 XAML 的 TypeConverter 实现,该方法必须接受要支持的类型的实例(或值)作为 value 参数。 如果 destinationType 参数为 String 类型,则返回的对象必须可强制转换为 String。 返回的字符串必须表示 value 的序列化值。 理想情况下,如果字符串是传递到同一转换器的 ConvertFrom 实现,则您选择的序列化格式应能够生成与该字符串相同的值,而不会丢失大量信息。

如果无法对值进行序列化,或者转换器不支持序列化,则 ConvertTo 实现必须返回 null,并可能会引发异常。 但如果引发了异常,则应报告无法使用该转换作为 CanConvertTo 实现的一部分,以便支持首先检查 CanConvertTo 以避免异常的最佳实践。

如果 destinationType 参数不是 String 类型,则您可以选择自己的转换器处理。 通常,您需要恢复到基实现处理,该处理在基本 ConvertTo 中会引发特定异常。

如果类型转换器必须具有从 .NET Framework XAML 服务对象编写器访问 XAML 服务的权限,但针对上下文进行的 GetService 调用不返回该服务,则会引发异常。

实现 CanConvertFrom

CanConvertFrom 实现应为类型为 String 的 sourceType 返回 true,否则遵从基实现。 不要从 CanConvertFrom 引发异常。

实现 CanConvertTo

CanConvertTo 实现应为类型为 String 的 destinationType 返回 true,否则遵从基实现。 不要从 CanConvertTo 引发异常。

应用 TypeConverterAttribute

为了使 .NET Framework XAML 服务将自定义类型转换器用作自定义类的当前类型转换器,必须将 .NET Framework attribute TypeConverterAttribute 应用于类定义。 通过特性指定的 ConverterTypeName 必须是自定义类型转换器的类型名称。 如果应用此特性,则当 XAML 处理器在属性类型使用自定义类类型的情况下处理值时,它可以输入字符串并返回对象实例。

您还可以基于每个属性提供类型转换器。 不应将 .NET Framework attribute TypeConverterAttribute 应用于类定义,而是将其应用于属性定义(是主定义,而不是其中的 get/set 实现)。 属性类型必须与自定义转换器处理的类型匹配。 应用此特性后,当 XAML 处理器处理该属性的值时,它可以处理输入字符串并返回对象实例。 如果选择使用 Microsoft .NET Framework 或某些其他库(其中无法控制类定义并无法应用 TypeConverterAttribute)中的属性类型,则每个属性类型转换器方法尤其有用。

若要为自定义附加成员提供类型转换行为,请将 TypeConverterAttribute 应用于该附加成员的实现模式的 Get 访问器方法。

通过标记扩展实现来访问服务提供程序上下文

可用的服务对于任何值转换器是相同的。 差别是每个值转换器接收服务上下文的方式不同。 主题 XAML 的类型转换器和标记扩展中介绍了如何访问服务以及可用的服务。

XAML 节点流中的类型转换器

如果使用 XAML 节点流,则尚不执行类型转换器的操作或最终结果。 在加载路径中,为了加载而最终需要进行类型转换的特性字符串在起始成员和结束成员中仍然作为文本值。 可以使用 XamlMember.TypeConverter 属性确定此操作最终所需的类型转换器。 但是,从 XamlMember.TypeConverter 获取有效值依赖于拥有 XAML 架构上下文,该上下文可以通过基础成员或该成员使用的对象值的类型访问此类信息。 调用类型转换行为也需要 XAML 架构上下文,因为它需要类型映射以及创建转换器实例。

请参见

参考

TypeConverterAttribute

概念

XAML 概述 (WPF)

其他资源

XAML 的类型转换器和标记扩展