XAML 中的空白处理
XAML 的语言规则说明了必须通过 XAML 处理器实现来处理的重要空白。 本主题介绍这些 XAML 语言规则。还介绍 XAML 处理器的 Windows Presentation Foundation (WPF) 实现所定义的其他空白处理,以及用于序列化的 XAML 编写器。
本主题包括下列各节。
- 空白定义
- 空白规范化
- 内部文本中的空白和字符串基元
- 保留空白
- 东亚字符
- 空白和文本内容模型
- 相关主题
空白定义
根据 XML,XAML 中的空白字符包括空格、换行符和制表符。 它们分别对应于 Unicode 值 0020、000A 和 0009。
空白规范化
默认情况下,当 XAML 处理器处理 XAML 文件时,将发生下列空白规范化:
移除东亚字符之间的换行符。 有关“东亚字符”的定义,请参见本主题后面的“东亚字符”一节。
将所有空白字符(空格、换行符和制表符)转换为空格。
删除所有连续的空格,将其替换为一个空格。
删除紧跟在开始标记后面的一个空格。
删除紧靠在结束标记前面的一个空格。
“Default”对应于 xml:space 特性的默认值所表示的状态。
内部文本中的空白和字符串基元
前面的规范化规则适用于 XAML 元素中的内部文本。 进行规范化后,XAML 处理器将所有内部文本转换为相应的类型,如下所示:
如果属性的类型不是一个集合,而是一个间接的 Object 类型,XAML 处理器将尝试使用其类型转换器转换为该类型。 如果这里的转换失败,将导致编译时错误。
如果属性的类型是一个集合,而且内部文本是连续的(没有介入的元素标记),则将内部文本分析为一个 String。 如果集合类型不能接受 String,则也会导致编译时错误。
如果属性的类型是 Object,则将内部文本分析为一个 String。 如果有介入的元素标记,则会导致编译时错误,因为 Object 类型表示单个对象(String 等)。
如果属性的类型是一个集合,而内部文本并不连续,则将第一个子字符串转换为一个 String 并添加为一个集合项,再将介入元素添加为一个集合项,最后将尾随子字符串(如果有)作为第三个 String 项添加到集合中。
保留空白
有几种方法可用于保留源 XAML 中的空白,以实现最终表示形式,这些方法不受 XAML 处理器空白规范化的影响。
xml:space="preserve":在需要保留空白的元素级指定此特性。 这样将保留所有空白,包括代码编辑应用程序为了以视觉上直观的嵌套形式“精美输出”对齐元素而添加的空格。 但是否呈现这些空白由包含元素的内容模型确定。 应避免在根级别指定 xml:space="preserve",因为大多数对象模型不会将空白视为重要,无论如何设置特性都是如此。 全局设置 xml:space 可能会对某些实现中的 XAML 处理(特别是序列化)的性能产生影响。 更好的做法是:专门在可呈现字符串中空白的元素级别或者在空白有意义的集合的元素级别设置该特性。
实体和不间断空格:XAML 支持在文本对象模型中放置任何 Unicode 实体。 您可以使用专用的实体,如不间断空格(在 UTF-8 编码中为  )。 还可以使用支持不间断空格字符的多格式文本控件。 使用实体模拟布局特征(如缩进)时应谨慎,因为实体的运行时输出会由于许多因素而不同,而影响实体输出的因素(如正确使用面板和边距)要多于用于在典型布局系统中生成缩进结果的功能。 例如,实体映射到字体,并且可以根据用户的字体选择来更改大小。
东亚字符
“东亚字符”是指一组 Unicode 字符,范围从 U+20000 到 U+2FFFD 以及 U+30000 到 U+3FFFD。 这个子集有时也称为“CJK 表意文字”。 有关更多信息,请访问 http://www.unicode.org。
空白和文本内容模型
在实际应用中,保留空白只涉及到所有可能的内容模型的一个子集。 该子集由一些内容模型组成,这些内容模型可以使用某种形式的单个 String 类型、专用的 String 集合,或者混合使用 String 与 IList 或 ICollection<T> 集合中的其他类型。
WPF 中的空白和文本内容模型
出于演示的目的,本节的其余部分引用由 WPF 定义的特定类型。 本主题介绍的空白处理功能一般来说与 .NET Framework XAML 服务和 WPF 都有关。 若要查看实际运行的此行为,可以试验一些 WPF XAML 标记并在对象图中查看结果,然后再序列化回标记。
这些内容模型内的默认行为是不将保留的任何空白视为有意义,即使对于可以使用字符串的内容模型而言,也是如此。 例如,ListBox 采用一个 IList,但是既不保留也不呈现空白(如每个 ListBoxItem 之间的换行符)。 如果尝试使用换行符作为 ListBoxItem 项的字符串之间的分隔符,则它根本不起作用;用换行符分隔的字符串被视为一个字符串和一个项。
将空白视为有意义的那些集合通常是流文档模型的一部分。 支持空白保留行为的主要集合是 InlineCollection。 此集合类使用 WhitespaceSignificantCollectionAttribute 进行声明;如果找到此特性,XAML 处理器将认为集合内的空白有意义。 在标有 WhitespaceSignificantCollectionAttribute 的集合中,xml:space="preserve" 和空白的组合意味着保留并呈现所有空白。 在 WhitespaceSignificantCollectionAttribute 中,xml:space="default" 和空白的组合将导致前面介绍的初始空白规范化,规范化的结果将在某些位置留下一个空白,这些空白将保留并呈现。 需要哪种行为由您自己而定,而您应该有选择地使用 xml:space 以实现所需的行为。
此外,流文档模型中暗含换行符的某些内联元素不应特意引入多余的空白,即使在空白有意义的集合中也是如此。 例如,在 HTML 中,LineBreak 元素与 <BR/> 标记的作用相同,但出于标记可读性的考虑,LineBreak 通常与后续文本之间用一个编写的换行符来分隔。 该换行符不应规范化为下一行的前导空格。 为了实现该行为,LineBreak 元素的类定义将应用 TrimSurroundingWhitespaceAttribute,该属性然后被 XAML 处理器解释为始终裁剪 LineBreak 周围的空白。