XAML 中的空白处理

XAML 的语言规则规定有意义的空白必须由 XAML 处理器实现进行处理。 本文介绍这些 XAML 语言规则。 它还介绍了由进行序列化的 XAML 处理器和 XAML 编写器的 Windows Presentation Foundation (WPF) 实现定义的其他空白处理。

空格的定义

与 XML 一致,XAML 中的空白字符包括空格、换行符和制表符。它们分别对应 Unicode 值 0020、000A 和 0009。

空白规范化

默认情况下,当 XAML 处理器处理 XAML 文件时,将发生下列空白规范化:

  1. 删除中文字符间的换行符。 有关此术语的定义,请稍后参阅本主题中的“中文字符”一节。

  2. 将所有空白字符(空格、换行符、制表符)都转换为空格。

  3. 删除所有连续的空格,并替换为一个空格。

  4. 删除开始标记后紧跟的一个空格。

  5. 删除结束标记前紧跟的一个空格。

“默认”对应于由 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 表意文字”。 有关详细信息,请参阅 https://www.unicode.org

空白和文本内容模型

在实践中,保留空白只与所有可能的内容模型的一个子集有关。 该子集由内容模型组成,这些模型可以采用某种形式的单独 String 类型、专用 String 集合,或 StringIListICollection<T> 集合中其他类型的混合。

WPF 中的空白和文本内容模型

为了便于说明,此部分的其余部分引用由 WPF 定义的特定类型。 本文中描述的空白处理功能通常与 .NET XAML 服务和 WPF 相关。 若要查看运行中的此行为,可以使用一些 WPF XAML 标记进行试验,在对象图中查看结果,然后重新序列化为标记。

甚至对于可以采用字符串的内容模型,这些内容模型内的默认行为是,保留的任何空白均不被视为有意义。 例如,ListBox 采用 IList,但不会保留且不会呈现空白(如每个 ListBoxItem 之间的换行符)。 如果尝试使用换行符作为 ListBoxItem 项的字符串之间的分隔符,则完全不适用;由换行符分隔的字符串将被视为一个字符串和一个项。

将空白视为有意义的集合通常是流文档模型的一部分。 支持空白保留行为的主要集合是 InlineCollection。 此集合类与 WhitespaceSignificantCollectionAttribute 一起声明;找到此属性时,XAML 处理器会将集合内的空白视为有意义。 xml:space="preserve"WhitespaceSignificantCollectionAttribute 表示的集合内的空白的组合是保留并呈现所有空白。 xml:space="default"WhitespaceSignificantCollectionAttribute 内空白的组合导致前文所述的初始空白规范化,这会在某些位置留下一个空格,而这些空格将被保留并呈现。 需要哪种行为由你决定,并且应有选择地使用 xml:space 以启用需要的行为。

此外,隐含流文档模型中换行符的某些内联元素应有意不引入额外空格,即使是在有意义的空白集合中也是如此。 例如,LineBreak 元素具有与 HTML 中 <BR/> 标记相同的目的,为了标记的可读性,通常通过编写的换行符将 LineBreak 与任何后续文本分开。 不应标准化该换行符以使它成为后续行中的前导空格。 要启用此行为,则 LineBreak 元素的类定义需应用 TrimSurroundingWhitespaceAttribute,随后由 XAML 处理器进行解释,这意味着 LineBreak 周围的空白始终被裁剪。

另请参阅