WPF RichTextBox打印预览功能实现方案咨询
WPF RichTextBox 打印预览实现方案
我之前开发WPF文本编辑器时也踩过这个坑——RichTextBox自带的打印功能效果拉胯,而且原生没提供现成的打印预览控件,得自己动手搭。下面给你两个经过验证的可行方案,都是基于FlowDocument(RichTextBox的内容载体)来实现的:
方案一:自定义打印预览对话框(最灵活)
这个方案是自己做一个带DocumentViewer的窗口,把RichTextBox的内容克隆后放到预览控件里,同时集成打印功能,完全可控。
步骤1:创建预览窗口的XAML
新建一个Window(比如叫PrintPreviewWindow),布局很简单,核心就是DocumentViewer加操作按钮:
<Window x:Class="YourEditorNamespace.PrintPreviewWindow" Title="打印预览" Width="800" Height="600"> <DockPanel> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="10"> <Button x:Name="btnPrint" Content="打印" Width="80" Margin="0 0 10 0" Click="BtnPrint_Click"/> <Button x:Name="btnClose" Content="关闭" Width="80" Click="BtnClose_Click"/> </StackPanel> <DocumentViewer x:Name="documentViewer"/> </DockPanel> </Window>
步骤2:克隆RichTextBox的FlowDocument
直接用原RichTextBox的Document会导致预览时的操作同步到原编辑器,所以必须深克隆一份:
private FlowDocument CloneRichTextBoxDocument(RichTextBox rtb) { // 通过Xaml序列化实现深拷贝,完整保留格式 var stringWriter = new StringWriter(); XamlWriter.Save(rtb.Document, stringWriter); var stringReader = new StringReader(stringWriter.ToString()); return (FlowDocument)XamlReader.Load(stringReader); }
步骤3:打开预览窗口并绑定内容
在主编辑器窗口的“打印预览”按钮点击事件里添加逻辑:
private void BtnPrintPreview_Click(object sender, RoutedEventArgs e) { // 克隆文档,避免影响原编辑器内容 var clonedDoc = CloneRichTextBoxDocument(yourRichTextBox); // 设置打印参数,确保预览和打印效果一致(以A4纸为例) clonedDoc.PageWidth = 8.5 * 96; // 96DPI下的A4宽度 clonedDoc.PageHeight = 11 * 96; // 96DPI下的A4高度 clonedDoc.PagePadding = new Thickness(96); // 1英寸边距 // 打开预览窗口 var previewWindow = new PrintPreviewWindow(); previewWindow.documentViewer.Document = clonedDoc; previewWindow.ShowDialog(); }
步骤4:预览窗口的打印逻辑
在PrintPreviewWindow的后台代码里实现打印和关闭功能:
private void BtnPrint_Click(object sender, RoutedEventArgs e) { var printDialog = new PrintDialog(); // 默认设置为A4纸 printDialog.PrintTicket.PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOC4); if (printDialog.ShowDialog() == true) { documentViewer.PrintDocument(printDialog.PrintTicket); } } private void BtnClose_Click(object sender, RoutedEventArgs e) { Close(); }
方案二:简化版——用PrintDialog结合临时FlowDocument
如果不需要单独的预览窗口,也可以直接借助PrintDialog的原生预览功能(部分系统支持):
private void BtnPrintWithPreview_Click(object sender, RoutedEventArgs e) { var clonedDoc = CloneRichTextBoxDocument(yourRichTextBox); clonedDoc.PageWidth = 8.5 * 96; clonedDoc.PageHeight = 11 * 96; clonedDoc.PagePadding = new Thickness(96); var printDialog = new PrintDialog(); // 绑定克隆后的文档到打印对话框 printDialog.PrintDocument(((IDocumentPaginatorSource)clonedDoc).DocumentPaginator, "你的编辑器文档"); // 弹出打印对话框,部分系统会显示预览选项 if (printDialog.ShowDialog() == true) { printDialog.PrintDocument(((IDocumentPaginatorSource)clonedDoc).DocumentPaginator, "你的编辑器文档"); } }
关键注意事项
- 必须克隆文档:直接引用原RichTextBox的Document会导致预览时的操作(比如滚动、选中文本)同步到原控件,深拷贝是必要的。
- 统一DPI和纸张设置:FlowDocument的PageWidth/PageHeight要和打印纸张一致(用96DPI换算,WPF默认DPI为96),否则预览和打印格式会出现偏差。
- 复杂格式兼容:Xaml序列化克隆的方式可以完整保留图片、表格等复杂元素的格式,比直接复制Blocks更可靠。
内容的提问来源于stack exchange,提问作者story sv




