WPF 流文档处理与打印功能实现
WPF 提供了两种文档模型:固定文档和流文档。
固定文档采用预定义布局,适合精确打印需求,例如报表或出版物,其遵循 XPS 标准。流文档则具备自适应性,能够根据显示区域动态调整内容布局,适用于屏幕阅读场景,比如应用程序的帮助文档。
WPF 使用不同的控件来承载这两类文档:
- DocumentViewer:用于展示固定文档。
- FlowDocumentReader、FlowDocumentPageViewer 和 FlowDocumentScrollViewer:专为流文档设计。其中 FlowDocumentScrollViewer 支持滚动浏览,而 FlowDocumentPageViewer 则按页展示文档内容。
构建流文档
流文档由一系列内容元素构成,这些元素分为两类:Block(块级)和 Inline(内联)。
Block 元素
这类元素通常作为容器使用,常见的包括:
- Paragraph:表示段落,可包含多个内联元素。
- List:用于创建项目符号或编号列表。
- Table:用于组织表格结构的数据。
- Section:无默认样式,主要用于包装一组块元素以便统一设置格式。
- BlockUIContainer:可在文档中嵌入任意 UI 控件。
常用的格式控制属性有:LineHeight 设置行高,TextAlignment 指定文本对齐方式。
示例:使用 Paragraph 显示文本
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph Name="paragraph">Hello this is China</Paragraph>
<Paragraph>This is a second paragraph</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
可通过代码修改段落内容:
((Run)paragraph.Inlines.FirstInline).Text = "again";
创建列表项
<Paragraph>Top programming languages</Paragraph>
<List>
<ListItem>
<Paragraph>C#</Paragraph>
<Paragraph>C++</Paragraph>
</ListItem>
</List>
<Paragraph>To-do List</Paragraph>
<List MarkerStyle="Decimal">
<ListItem><Paragraph>WPF</Paragraph></ListItem>
<ListItem><Paragraph>Winform</Paragraph></ListItem>
</List>
构建表格
<Table BorderBrush="Black" BorderThickness="1">
<Table.Columns>
<TableColumn Width="*"/>
<TableColumn Width="3*"/>
<TableColumn Width="*"/>
</Table.Columns>
<TableRowGroup Paragraph.TextAlignment="Left">
<TableRow FontWeight="Bold">
<TableCell BorderBrush="Black" BorderThickness="1">
<Paragraph>Rank</Paragraph>
</TableCell>
<TableCell><Paragraph>Name</Paragraph></TableCell>
<TableCell><Paragraph>Population</Paragraph></TableCell>
</TableRow>
<TableRow>
<TableCell><Paragraph>1</Paragraph></TableCell>
<TableCell><Paragraph>Rome</Paragraph></TableCell>
<TableCell><Paragraph>1000000</Paragraph></TableCell>
</TableRow>
</TableRowGroup>
</Table>
组合内容区块
<Section FontSize="20" Background="Red" Paragraph.LineHeight="1">
<Paragraph>this is first paragraph</Paragraph>
<Paragraph>this is second paragraph</Paragraph>
</Section>
插入控件
<BlockUIContainer>
<Button Content="Click Me"/>
</BlockUIContainer>
Inline 元素
此类元素必须位于 Block 内部,常用于富文本渲染:
- Run:承载纯文本内容。
- Span:可用于包裹其他内联元素。
- LineBreak:强制换行。
- InlineUIContainer:嵌入 UI 元素。
- AnchoredBlock:如 Figure 或 Floater,用于浮动定位。
基本用法
<Paragraph>
<Run>Hello World</Run>
</Paragraph>
实现文档打印
通过将 FlowDocument 转换为 XPS 文档,并利用 XpsDocumentWriter 进行写入操作,可以完成打印任务。
生成内存中的 XPS 文件
MemoryStream memoryStream = new MemoryStream();
Package pkg = Package.Open(memoryStream, FileMode.Create, FileAccess.ReadWrite);
Uri docUri = new Uri("pack://temp.xps");
PackageStore.RemovePackage(docUri);
PackageStore.AddPackage(docUri, pkg);
XpsDocument xpsDoc = new XpsDocument(pkg, CompressionOption.Normal, docUri.ToString());
执行打印流程
XpsDocumentWriter xpsWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
using (FileStream fs = File.Open("OrderTemplate.xaml", FileMode.Open))
{
FlowDocument doc = (FlowDocument)XamlReader.Load(fs);
xpsWriter.Write(((IDocumentPaginatorSource)doc).DocumentPaginator);
docViewer.Document = xpsDoc.GetFixedDocumentSequence(); // 预览
}
xpsDoc.Close();
memoryStream.Dispose();
