这一章介绍Flow流。
本章共计27个示例,全都在VS2008下.NET3.5测试通过,点击这里下载:Flow.rar
本章的所有示例都使用了FlowDocument来对文本进行布局。
为此需要先介绍FlowDocumentReader——这是一个提供用来查看流内容并内置有对多种查看模式的支持的控件。

FlowDocumentReader 包括一些功能,使用户能够在各种查看模式之间动态选择,其中包括单页(一次一页)查看模式、一次两页(书本阅读格式)查看模式和连续滚动(无限)查看模式。 如果不需要在不同的查看模式之间动态切换的功能,则选择一些使用某种固定的查看模式的轻量流内容查看器。FlowDocumentPageViewer 以单页查看模式显示流内容,而 FlowDocumentScrollViewer 以连续滚动模式显示流内容。 有关可用的显示模式的更多信息,请参见 FlowDocumentReaderViewingMode。
此外还要介绍FlowDocumentScrollViewer:以连续滚动模式显示内容。默认情况下,总是显示垂直滚动条,而水平滚动条则根据需要显示,而且它的默认UI不包括工具栏。
最后介绍FlowDocumentPageViewer:以“一次一页”的查看模式显示内容

总结:
FlowDocumentPageViewer 和 FlowDocumentScrollViewer 都固定采用某种特定查看模式。另一方面,FlowDocumentReader 包含若干功能,允许用户在各种查看模式(由 FlowDocumentReaderViewingMode 枚举提供)之间进行动态选择,但其性能不如 FlowDocumentPageViewer 或 FlowDocumentScrollViewer。
这三个控件都能且只能承载一个 FlowDocument,
1.FlowDirectionLayout
这个实例展现了FlowDirection的两个枚举值的效果,指定文本和用户界面 (UI) 元素的内容流动方向,其中:
LeftToRight 指示内容应从左向右流动
RightToLeft 指示内容应从右向左流动
注:内容的流动方向通常与所表示语言的固有流动方向相对应。例如,希伯来语和阿拉伯语是从右向左流动的语言,英语、德语和俄语是从左向右流动的语言。
XAML中使用如下:
以下是引用片段: <FlowDocumentReader> <FlowDocument FontFamily="Arial" Name="tf1" > <Paragraph FlowDirection="LeftToRight"> Lorem ipsum dolorctetuer adipiscing elit, sed diam nonummy </Paragraph> </FlowDocument> </FlowDocumentReader> |
在C#代码中:
| 以下是引用片段: Paragraph par = new Paragraph(new Run("This paragraph will flow from left to right.")); par.FlowDirection = FlowDirection.LeftToRight; |
这个实例展现了TextTrimming的三个枚举值的效果,描述当文本溢出其包含框的边缘时如何修整文本:默认为None
| 以下是引用片段: <TextBlock TextTrimming="None"… /> |
CharacterEllipsis 在字符边界处修整文本。将绘制省略号 (...) 来替代剩余的文本
WordEllipsis 在单词边界处修整文本。将绘制省略号 (...) 来替代剩余的文本

| 以下是引用片段: <TextBlock Name="txt2" TextWrapping="Wrap"… /> |
3.TextWrapProperty
这个实例展现了TextWrapping的三个枚举值的效果,指定文本在到达包含框的边缘时是否换行:默认为NoWrap。
| 以下是引用片段: <FlowDocumentReader Name="FlowDocRdr" Grid.Row="1" /> |
NoWrap 不换行
Wrap 如果行溢出可用块宽度则进行换行
WrapWithOverflow 如果行溢出可用块宽度则进行换行,但是有例外,如下
后两个枚举值效果基本上一样,只是对于非常长的单词会有特殊处理。对于WrapWithOverflow,如果换行算法无法确定换行时机(比如说,被限制在不允许滚动的固定宽度容器中的非常长的单词的情况),则行可能会溢出块宽度。而对于Wrap,则没有例外——不管多长的单词都会换行而不会超过块的宽度。
4.FlowDocument_LoadSave
这个例子演示了如何加载以FlowDocument开头的XAML到当前的FlowDocumentReader中,以及如何将一个FlowDocument片段保存为一个XAML文件。
XAML中有一个空的FlowDocumentReader:
主要的逻辑在后台代码中:为此使用了XAML中的XamlReader和XamlWriter
先看如何加载一个XAML,并设置给FlowDocumentReader,这里先打开OpenFileDialog携带的加载路径,并将其装换为FileStream:
| 以下是引用片段: OpenFileDialog openFile = new OpenFileDialog(); FileStream xamlFile = openFile.OpenFile() as FileStream; FlowDocument content = XamlReader.Load(xamlFile) as FlowDocument; FlowDocRdr.Document = content; |
| 以下是引用片段: SaveFileDialog saveFile = new SaveFileDialog(); FileStream xamlFile = saveFile.OpenFile() as FileStream; XamlWriter.Save(FlowDocRdr.Document, xamlFile); xamlFile.Close(); |
5.FlowDoc_OptimalParagraph
这个例子演示了FlowDocument的5个属性:
IsHyphenationEnabled
获取或设置一个值,该值指示是否启用文字的自动断字和添加连字符功能。
自动断字功能使 FlowDocument 能够根据当前布局情况自动分断文字并添加连字符。这使得在一行中开始的某个较长的单词能够继续到下一行,从而使空白在两端对齐的文本中能够更为均匀地分布。单词根据标准语法规则进行分断和添加连字符。自动断字当与最佳段落布局(由 IsOptimalParagraphEnabled 属性表示)结合使用时尤其有效。
IsOptimalParagraphEnabled
获取或设置一个值,该值指示是否启用最佳段落布局功能
最佳段落布局功能即按照使空白尽可能均匀分布的方式来布局 FlowDocument 中的段落。从理论上而言,这消除了因行对齐文本及其他布局程序而产生的混乱的空白,从而可提供最佳的阅读体验。
在本例中,IsHyphenationEnabled和IsOptimalParagraphEnabled同时为true,可以获得比较好的视觉效果。
IsColumnWidthFlexible
获取或设置一个值,该值指示 ColumnWidth 值是可变的(true)还是固定的(false)。
IsColumnWidthFlexible 属性确定任何多余的内容区域宽度(即页宽与内容在布局后的宽度之间的差)在各列之间的分配方式。如果设置为 true,则表示将额外的空间平均分配给每一列。在这种情况下,调整后的列宽可能会大于 ColumnWidth 属性所指定的宽度。如果设置为 false,则表示将额外的空间分配给页面右侧的边距。在这种情况下,列宽始终为 ColumnWidth 属性所指定的宽度(只要该宽度小于页宽减去所有 PagePadding)。
ColumnWidth
获取或设置 FlowDocument 中列的所需最小宽度。
默认值为 Double.NaN,导致无论页面宽度如何,都只显示一列。
ColumnGap
获取或设置列间隔值,该值指示 FlowDocument 中各列之间的间距。
注:列间隔不能超过当前 PageWidth 减去所有 PagePadding。如果 ColumnGap 属性的值超过此限制,则会减小有效列间隔以遵从此限制
6.FlowFormatCatalog
这个例子演示了各种流内容元素:
Bold 元素
BreakPageBefore 属性
FontSize 属性
Italic 元素
LineBreak 元素
List 元素
ListItem 元素
Paragraph 元素
un 元素
Section 元素
Span 元素
Variants 属性(上标和下标)
Underline 元素
另外,在FlowDocument中,使用Paragraph标签作为文本的容器。使用LineBreak可以换行:
| 以下是引用片段: <Paragraph> <LineBreak/> </Paragraph> |
还有就是,一加载这个FlowDocument,就会自动使用来生成FlowDocumentPageViewer内容。因为这个例子的XAML以FlowDocument开始,而FlowDocumentPageViewer无论是否显示包在FlowDocument的外面,都会被调用来生成内容。
7.FontFamilySample
这个例子演示了如何动态改变文本的FontSize和FontFamily。同时,我们还可以改变它的FontStretch、FontWeight、以及FontStyle
注:这里FontStyle指的是“Normal”、“Italic”或“Oblique
8.TableCsharpSample
这个例子完全用C#构造出一个Table来
一个Table中可以有多个TableRowGroup:
currentRow = table1.RowGroups[0].Rows[4];

9.TableElementSample
这个例子演示了如何在XAML中使用Table。
首先要定义列,方式同Grid一样(当然也可以不设置):
| 以下是引用片段: <Table> <Table.Columns> <TableColumn /> <TableColumn /> <TableColumn /> <TableColumn /> </Table.Columns> |
以下是引用片段: <TableRowGroup> <TableRow> <TableCell ColumnSpan="4"><Paragraph FontWeight="Bold">Planetary</Paragraph> </TableCell> </TableRow> |
TableCell 元素可承载从 Block 派生的一个或多个流内容元素。 TableCell 有效的内容元素包括:
BlockUIContainer
List
Paragraph
Section
Table
注:没有 TableCell 内容的内置数据绑定。
另外,只可以在TableCell中设置ColumnSpan和RowSpan:
<TableCell ColumnSpan="4" RowSpan="4">