XAML 的类型转换器概述
类型转换器为对象编写器提供逻辑,该逻辑从 XAML 标记中的字符串转换为对象图中的特定对象。 在 .NET XAML 服务中,类型转换器必须是派生自 TypeConverter的类。 某些转换器还支持 XAML 保存路径,并可用于在序列化标记中将对象序列化为字符串形式。 本主题介绍如何以及何时调用 XAML 中的类型转换器,并为 TypeConverter的方法替代提供实现建议。
类型转换概念
以下部分介绍了 XAML 如何使用字符串的基本概念,以及 .NET XAML 服务中的对象编写器如何使用类型转换器来处理 XAML 源中遇到的某些字符串值。
XAML 和字符串值
在 XAML 文件中设置属性值时,该值的初始类型是常规意义上的字符串,也是 XML 意义上的字符串属性值。 即使是其他基元(如 Double)最初也是 XAML 处理器的字符串。
在大多数情况下,XAML 处理器需要两段信息来处理属性值。 第一条信息是正在设置的属性的值类型。 定义属性值且在 XAML 中处理的任何字符串最终都必须转换为该类型的值或解析。 如果该值是 XAML 分析器(如数值)理解的基元,则尝试直接转换字符串。 如果属性的值引用枚举,则会检查所提供的字符串,以确定名称是否与该枚举中的命名常量匹配。 如果该值不是枚举中的分析器基元或常量名称,则适用类型必须能够提供基于转换后的字符串的值或引用。
注意
XAML 语言指令不使用类型转换器。
类型转换器和标记扩展
在检查属性类型和其他因素之前,标记扩展用法必须由 XAML 处理器处理。 例如,如果一个设置为属性的属性通常具有类型转换,但在特定情况下通过标记扩展的用法来设置,则标记扩展的行为优先处理。 需要标记扩展的一种常见情况是引用已存在的对象。 对于此方案,无状态类型转换器只能生成可能不需要的新实例。 有关标记扩展的详细信息,请参阅 XAML 标记扩展概述 。
本机类型转换器
在 Windows Presentation Foundation (WPF) 和 .NET XAML 服务实现中,某些 CLR 类型具有本机类型转换处理。 但是,这些 CLR 类型通常不被视为基元。 此类类型的一个示例是 DateTime。 原因之一是 .NET Framework 体系结构的工作原理:类型 DateTime 在 .NET 中最基本的库 mscorlib 中定义。 不允许将 DateTime 赋予来自另一个程序集的属性,这会引入依赖性(TypeConverterAttribute 来自 System)。 因此,不支持通过属性的通常类型转换器发现机制。 相反,XAML 分析器包含需要本机处理的类型的列表,并且处理这些类型与处理真实基元的方式类似。 对于 DateTime,此处理涉及调用 Parse。
实现类型转换器
以下各节讨论 TypeConverter 类的 API。
类型转换器
在 .NET XAML 服务下,用于 XAML 用途的所有类型转换器都是派生自基类 TypeConverter的类。 在 XAML 存在之前,TypeConverter 类存在于 .NET Framework 版本中;原始 TypeConverter 方案之一是为视觉设计器中的属性编辑器提供字符串转换。
对于 XAML,TypeConverter 的作用被扩大。 出于 XAML 目的,TypeConverter 是用于提供对某些到字符串和从字符串转换的支持的基类。 From-string 允许分析 XAML 中的字符串属性值。 To-string 可能允许将特定对象属性的运行时值处理回 XAML 中的属性进行序列化。
TypeConverter 定义了四个与转换到字符串和从字符串进行 XAML 处理相关的成员。
在这些成员中,最重要的方法是 ConvertFrom,该方法将输入字符串转换为所需的对象类型。 可以实现 ConvertFrom 方法,将更广泛的类型转换为转换器的预期目标类型。 因此,它可以用于超越 XAML 的目的,例如支持运行时转换。 但是,对于 XAML 使用,只有能够处理 String 输入的代码路径非常重要。
第二最重要的方法是 ConvertTo。 如果应用程序转换为标记表示形式(例如,如果将其保存为文件),ConvertTo 在 XAML 文本编写器的大型方案中参与以生成标记表示形式。 在这种情况下,XAML 的重要代码路径是调用方传递 destinationType
String。
CanConvertTo 和 CanConvertFrom 是服务查询 TypeConverter 实现的功能时使用的支持方法。 必须实现这些方法才能为转换器支持的等效转换方法的类型特定情况返回 true
。 出于 XAML 目的,这通常意味着 String 类型。
XAML 的文化信息和类型转换器
每个 TypeConverter 实现都可以唯一地解释转换的有效字符串,还可以使用或忽略作为参数传递的类型说明。 区域性和 XAML 类型转换的一个重要考虑因素是:尽管将可本地化字符串用作 XAML 支持的属性值,但不能将这些可本地化字符串用作具有特定区域性要求的类型转换器输入。 此限制是因为 XAML 属性值的类型转换器涉及使用en-US
文化的固定语言的 XAML 处理行为。 有关此限制的设计原因的详细信息,请参阅 XAML 语言规范([MS-XAML])或 WPF 全球化和本地化概述。
例如,在某些文化中,逗号而不是句号用作字符串形式数字的小数点。 这与许多现有类型转换器的行为相冲突,即使用逗号作为分隔符。 通过外围 XAML 中的 xml:lang
传递文化无法解决问题。
实现 ConvertFrom
要作为支持 XAML 的 TypeConverter 实现使用,该转换器的 ConvertFrom 方法必须接受字符串作为 value
参数。 如果字符串的格式有效,并且可由 TypeConverter 实现进行转换,则返回的对象必须支持转换为属性所期望的类型。 否则,ConvertFrom 的实现必须返回 null
。
每个 TypeConverter 实现都可以自行解释构成转换的有效字符串,同时还可以使用或忽略作为参数传递的类型说明或文化背景。 但是,WPF XAML 处理可能不会在所有情况下将值传递给类型描述上下文,也可能不会基于 xml:lang
传递区域性。
注意
请勿使用大括号({}),特别是左大括号({)作为字符串格式的元素。 这些字符被保留为标记扩展序列的入口和出口。
当类型转换器需要从 .NET XAML Services 对象编写器访问 XAML 服务时,而针对上下文的 GetService 调用未能返回该服务,那么引发异常是适当的。
实现 ConvertTo 函数
ConvertTo 可能用于序列化支持。 通过 ConvertTo 为自定义类型及其类型转换器提供序列化支持并不是绝对必要的。 但是,如果要实现控件,或使用序列化作为类的功能或设计的一部分,则应实现 ConvertTo。
要用作支持 XAML 的 TypeConverter 实现,该转换器的 ConvertTo 方法必须接受作为 value
参数支持的类型的实例(或值)。 当 destinationType
参数的类型为 String时,返回的对象必须能够转换为 String。 返回的字符串必须表示 value
的序列化值。 理想情况下,所选的序列化格式应能够生成与该字符串传递到同一转换器的 ConvertFrom 实现相同的值,而不会显著丢失信息。
如果无法序列化值或转换器不支持序列化,ConvertTo 实现必须返回 null
并引发异常。 但是,如果确实引发了异常,应该报告无法使用该转换作为 CanConvertTo 实现的一部分,从而支持首先检查 CanConvertTo 以避免异常的最佳实践。
如果 destinationType
参数的类型不是 String,则可以选择自己的转换器处理。 通常,恢复到基本实现处理,在基 ConvertTo 中引发一个特定异常。
如果类型转换器必须从 .NET XAML 服务对象编写器访问 XAML 服务,而针对上下文的 GetService 调用未能返回该服务,则应引发异常。
实现 CanConvertFrom
对于 String 类型的 sourceType
,CanConvertFrom 实现应返回 true
,否则应交由基本实现处理。 不要从 CanConvertFrom引发异常。
实现 CanConvertTo
CanConvertTo 实现应为类型为 String的 destinationType
返回 true
,否则应使用基本实现。 不要从 CanConvertTo引发异常。
应用 TypeConverterAttribute
要使自定义类型转换器作为 .NET XAML 服务的自定义类的类型转换器使用,必须在类定义中应用 TypeConverterAttribute。 通过属性指定的 ConverterTypeName 必须是自定义类型转换器的类型名称。 如果应用此属性,当 XAML 处理器处理属性类型使用自定义类类型的值时,它可以输入字符串并返回对象实例。
还可以按属性提供类型转换器。 而不是将 TypeConverterAttribute 应用于类定义,而是将其应用于属性定义(主定义,而不是其中 get
/set
实现)。 属性的类型必须与自定义类型转换器处理的类型匹配。 应用此属性后,当 XAML 处理器处理该属性的值时,它可以处理输入字符串并返回对象实例。 如果选择从 Microsoft .NET Framework 或无法控制类定义的其他库使用属性类型,并且不能在此处应用 TypeConverterAttribute,则每个属性类型转换器技术非常有用。
若要为自定义附加成员提供类型转换行为,请将 TypeConverterAttribute 应用于该附加成员实现模式中的 Get
访问器方法。
从标记扩展实现中获取服务提供商上下文
任何值转换器的可用服务都是相同的。 区别在于每个值转换器接收服务上下文的方式。 访问服务及可用服务被记录在主题 类型转换器和 XAML 标记扩展中。
XAML 节点流中的类型转换器
如果使用的是 XAML 节点流,则尚未执行类型转换器的操作或结束结果。 在一个加载路径中,需要进行类型转换以便加载的属性字符串在起始成员和结束成员之间保留为文本值。 可以使用 XamlMember.TypeConverter 属性来确定此操作最终所需的类型转换器。 但是,从 XamlMember.TypeConverter 获取有效值依赖于具有 XAML 架构上下文,该上下文可以通过基础成员或成员使用的对象值的类型访问此类信息。 调用类型转换行为还需要 XAML 架构上下文,因为这需要类型映射和创建转换器实例。
另请参阅
- TypeConverterAttribute
- 适用于 XAML 的
类型转换器和标记扩展 - XAML 概述 (WPF .NET)