技术开发 频道

WPF使用流文档灵活地显示内容

    创建流文档

    如何编写流文档?当然,开发人员始终可以使用诸如 XamlPad 等低级工具来编写流文档。但是,在现实环境下,这不大可能。通常,流文档是使用 WYSIWYG 编辑器或通过从现有文档格式进行的内容转换来创建的。由于流文档可以使用 XAML 定义,因此转换现有 XML 内容特别简单。但也可以转换 HTML 和 Word 文档,而无需付出过大的精力(尽管需要编码,因为迄今为止尚未出现现成工具)。

    对于 WYSIWYG 编辑,WPF 提供了一个现成的控件。WPF RichTextBox 控件可以本机编辑 XAML 流文档。该控件名称让人误以为它是专门针对 RTF 格式。尽管这个控件也支持 RTF,但实际上它主要用于流文档。事实上,该控件实际上会反映流文档查看控件,只不过它也支持编辑。有些人甚至会说,RichTextBox 控件应该被视为显示流文档的另一种方式。

    将下列示例键入 XamlPad 中,以查看运行中的 RichTextBox 控件:
<RichTextBox xmlns=’http://schemas.microsoft.com/ winfx/2006/xaml/presentation’ xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’> <FlowDocument> <Paragraph> The quick brown fox jumps over the lazy dog. </Paragraph> </FlowDocument> </RichTextBox>
    恰如读取器控件一样,RichTextBox 也有一个 Document 属性,您可以自动以此会话中的流文档填充其值。这实际上会创建一个与 FlowDocumentScrollViewer 控件看起来很相似的 UI,只不过其中的文本可以编辑。请注意,此文本框控件始终以滚动方式处理流文档。在分页或多列模式下,无法在 RichTextBox 中编辑流文档。不过,编辑操作的结果是一个标准流文档,该文档可以使用您已看到的任何一种查看器机制显示,其中包括多列和分页模式。

    关于 RichTextBox,值得一提的其中一项功能是集成的拼写检查。您可以按如下所示启用该功能: 
<RichTextBox SpellCheck.IsEnabled=”true”> <FlowDocument>...</FlowDocument> </RichTextBox>
    图 13 显示了运行中的拼写检查程序。


    图 13 带有拼写检查功能的 RichTextBox 控件 (单击该图像获得较大视图)
使用此控件唯一复杂的地方是加载与保存。在许多情形下,您可能不会像在之前的例子中那样,将 RichTextBox 内容编码到 UI XAML 中,而是要动态加载和保存文档。RichTextBox 中文本的加载操作与为查看器控件加载流文档相同(见上文)。保存文档本质上则完全相反:您要先拿到文档对象,然后将其序列化回 XAML,如下所示:
System.Windows.Markup.XamlWriter. Save(richTextBox.Document)
    这会将 XAML 作为一个字符串返回,然后您可以将其存储到文件或数据库中,或者使用您能想到的任何其他方式。

    RichTextBox 非常方便,不过在这里还是要提醒几句话。虽然流文档代表了可用于呈现屏幕文档的最复杂的技术,但 RichTextBox 控件却一点也不复杂。它是编辑小型文档和文本段的较好选择,但是您不会用它来编写书籍、杂志或营销手册。对于这些长格式,它的呈现过于简单,因为它不支持除滚动布局之外的其他任何布局(也就是说,还没有一种很好的可视方式可用于创建我稍后将谈到的高级布局)。同样,用于保存文档的方法也经常不尽人意。XmlWriter 类只是使用实时的内存中文档,并将其转换为 XAML,但遗憾的是,对于大规模的流文档操作非常重要的许多概念(例如样式),它并未注意。结果,尽管 XAML 忠实地保存了文档的外观,但文档看起来往往不太清爽,并且很大。RichTextBox 控件当然还是很有用的,但是别指望将它作为屏幕内容的桌面出版解决方案(虽然这类应用程序非常急需)。

    探究布局可能性

    至此您已了解了如何编写和查看流文档,接着让我们回到文档本身,看看更多的功能。流文档非常复杂,探究所有可用功能超出了本文范围,不过我想再讨论几项功能。

    其中一项一直让我着迷的功能是“非常好的段落”。启用该功能后,可以在指定段落内尽可能平均地分布空白,从而带来显著改进的阅读体验。“非常好的段落”特别适合与另一项内置功能“断字”搭配使用,该功能(居然)会执行动态整个流文档或者个别段落的断字。

    启用非常好的段落和断字功能是项非常简单的操作:
<FlowDocument IsOptimalParagraphEnabled=”true” IsHyphenationEnabled=”true”>

    图 14 显示的是相同的文档,只是呈现时启用或禁用了这些功能。两个版本间的区别非常细微,但是非常重要。请注意,左边的版本看起来更平和,主要因为词与词之间的空白分布得更平均,且从整体上减少了。特别是在屏幕上阅读大量文本时,这个看起来细小的区别会变得极为重要。



图 14 非常好的段落和断字 (单击该图像获得较大视图)
    如您所见,FlowDocumentReader 控件采取多列的方法呈现文本。这是另一项非常重要的可读性功能,因为人们不喜欢读跨越整个宽屏显示页面宽度的一行行文字。实际列宽因各种因素会有所不同,例如用于内容显示的可用总宽度、缩放系数和定义的列宽等。流文档的默认列宽为字体大小的 20 倍,默认字体大小约为 300 个与设备无关的像素(3 1/8 英寸的精确尺寸显示)。您可以很轻松地覆盖此默认设置:
<FlowDocument ColumnWidth=”400”>
    这会产生宽度约 400 像素的列。不过,还有其他一些因素会影响实际宽度。举例来说,如果缩放比例是 50%,那么实际列宽就只有 200 像素。另外,到目前为止,列宽更多地会被看作最小列宽。这意味着,如果可用总宽度为 900 像素,要呈现结果包含两列,并且要充分填满这整个 900 像素的话,就要让每列的宽度都超过定义的 400 像素。通常都需要这样,因为它会让呈现结果看起来非常美观。不过,如果您不想执行该行为,而只希望列宽实际就是 400 像素的话,可以确保列宽不是灵活可变的:
<FlowDocument ColumnWidth=”400” IsColumnWidthFlexible=”false”>
    现在,所有列都正好是 400 像素(100% 缩放),剩余空间就让它显示为空白。

    另一个您可能想尝试的与列相关的设置是列之间的空隙。这可以通过 ColumnGap 属性调整(此设置也是基于与设备无关的像素数):
<FlowDocument ColumnGap=”25”>
  
0
相关文章