用WPF实现打印及打印预览
应该说,WPF极大地简化了我们的打印输出工作,想过去使用VC++做开发的时候,打印及预览可是一件极麻烦的事情,而现在我不会再使用C++来做Windows的桌面应用了——性价比实在太低。
WPF的打印功能是很强大而简便的,它甚至能够直接打印界面上的内容,包括各种控件的显示内容,例如你在界面上摆放了一个datagrid控件,画了一个五角星,或写了一段文字,都可以直接打印出来,这里有一篇文章很简单明了地说明了这个功能:
http://www.cnblogs.com/gnielee/archive/2010/07/02/wpf-print-sample.html
这种做法是非常直截了当的,但恐怕不是很适合我们一般的应用,我们更多的时候需要自适应纸张,表格输出,自动分页,还有分页预览……
自己设计分页是非常麻烦的事情,没做过的人恐怕没法理解为什么,我这里插点题外话提一下,为什么分页难做?那是因为:你不真正把文档打印出来,你就不知道到底要在什么地方分页。举个最简单的例子,就一大段文本,给你打印,你认为到第几个字要另开一页?你估算了一下:一行20个字,我的打印纸一共20行,所以到第400个字的时候分页。——Too simple,你没考虑一行的字数根本就是不确定的(字符非等宽),也没考虑回车换行所产生的空行,更没考虑字体大小,行间距等影响因素,另外还有单词自适应因素,最后还有纸张大小……Oh,my god,这简直没法做,是的,自己很难做的,一个比较笨但有效的方法是“模拟打印”,用二分法找到开始分页的那个点,我以前做过的一个手机看书软件就是这么干的,而真实的分页算法是很复杂的,所幸的是这次不需要我们来做了。下面是我写的一个demo。

这是打印预览效果:

代码并不多。设计的思路就是:文档模版(xaml)+数据(.net对象)=打印输出
文档模版可以单独创建,右击你的WPF工程,Add - New Item - Flow Document(WPF),Visual Studio并没有提供这个xaml的预览,这点不得不说是个缺陷,微软的理由是这种Flow Document的显示需要一个容器,单独的Flow Document(流文档)是没法预览的,你必须把它放在一个容器中才可以,流文档的容器有FlowDocumentScrollViewer,FlowDocumentPageViewer,FlowDocumentReader,另外还有DocumentViewer,这个只支持固定流文档(只读)。关于流文档及其打印方面的技术在《WPF编程宝典》一书中都有具体讲述,建议大家要详细了解的话先去阅读一下此书,下面主要是一些书中没有的内容。
打印预览,我们这次选择了DocumentViewer,因为它直接就带有很好的分页功能,我们只需要生成固定文档(XPS),然后交给它,它就能很好的将内容预览出来——太棒了。
现在我们大致看看这个流文档模版的内容:

<Table FontSize="16">
<Table.Columns>
<TableColumn Width="200"></TableColumn>
<TableColumn Width="600"></TableColumn>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
订单号
</Paragraph>
</TableCell>
<TableCell>
<Paragraph>
<Run Text="{Binding OrderNo}"></Run>
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Paragraph>
客户名称
</Paragraph>
</TableCell>
<TableCell>
<Paragraph>
<Run Text="{Binding CustomerName}"></Run>
</Paragraph>
</TableCell>
</TableRow>
<!-- 省略一大段 -->
</TableRowGroup>
</Table>

我把多余的内容去掉了,现在注意看“<Run Text="{Binding OrderNo}"></Run>”这个地方,我将这个Run的Text属性绑定到DataContext的OrderNo去了,也就是说,它会根据数据的内容,渲染出不同的结果。
这里一切OK,但最大的问题来了:流文档的Table却不能跟UIElement的DataGrid控件那样能动态地根据数据的条目数渲染出相应的行!也就是说Table的行数是固定的,流文档上的对象是静态的,所以我们只能用后台代码来手工改变它了,这是相当不方便的地方……我定义了这么一个接口来做这种工作:
public interface IDocumentRenderer
{
void Render(FlowDocument doc, Object data);
}
创建一个对象,实现这个接口,然后根据data的内容,往doc里对应的地方插入行。
另外还需要特别说明的是代码中使用了一些BeginInvoke,也许大家不太了解那是什么意思,为什么需要这么麻烦?其实,那是因为你给Document的DataContext赋值的时候,Document的内容并不是马上改变的,不信你可以把我写的这些BeginInvoke改为直接调用,然后看看打印预览的文档内容,是不是哪些binding的地方还是空白的?所以需要一个“延后”调用。关于BeginInvoke的内容可以看我这篇blog:
http://www.cnblogs.com/guogangj/archive/2013/01/22/2870590.html
最后,主界面上的“直接打印”为了防止用户连续点击,需要在点了一下之后把它变灰,然后过几秒钟之后再把它变亮。
最后的最后:完整代码下载
用WPF实现打印及打印预览的更多相关文章
- Lodop中特殊符号¥打印设计和预览不同
Lodop中¥符号样式改变问题 Lodop中对超文本样式的解析,虽然说是按照调用的本机ie引擎,但是调用的ie版本可能不同,导致在ie下是一种样式,预览又是另一种样式.可能是有些样式没有具体设置,走的 ...
- JS Web打印,实现预览新样式
问题描述: JS实现Web打印,要求打印前一种样式,打印预览时新样式 问题解决: (1)设置打印时的css样式,设置打印前的css样式 注: 以上为print. ...
- asp.net调用Lodop实现页面打印或局部打印,可进行打印设置或预览
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="WebPrint.aspx.cs ...
- WPF使用AForge实现Webcam预览(二)
本文主要介绍如何让摄像头预览界面的宽高比始终在16:9. 首先我们需要修改一下上一篇随笔实现的UI界面,让Grid变成一个3*3的九宫格,预览界面位于正中间.Xaml示例代码如下: <Windo ...
- WPF使用AForge实现Webcam预览(一)
本文简略地介绍一下如果使用AForge来实现前置/后置摄像头的预览功能. 要使用AForge,就需要添加AForge NuGet相关包的引用,这些包依赖的其他包会自动安装. AForge.Contro ...
- css去掉使用bootstrap框架后打印网页时预览效果下的超链接
在我们写网页的时候,超链接是链接各个页面的桥梁,也是搜索引擎爬虫(spider)收录网站页面的关键,因此,在每个网页中会有许多的超链. 今天,一个同行妹妹在使用了bootstrap框架来搭建自己的网站 ...
- java原装代码完成pdf在线预览和pdf打印及下载
这是我在工作中,遇到这样需求,完成需求后,总结的成果,就当做是工作笔记,以免日后忘记,当然,能帮助到别人是最好的啦! 下面进入正题: 前提准备: 1. 项目中至少需要引入的jar包,注意版本: a) ...
- Lodop打印设计矩形重合预览线条变粗
LODOP中的打印设计是辅助进行开发的,实际打印效果应以预览为准,很多效果都是在设计界面显示不出来,或设计和预览界面有差异.例如add_print_text文本的字间距.行间距,旋转,还有允许标点溢出 ...
- Winform中使用FastReport实现自定义PDF打印预览
场景 Winform中使用FastReport实现简单的自定义PDF导出: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1009 ...
随机推荐
- 15、USB摄像头图片采集+QT显示
一.Qt的下载和的安装 关于Qt的安装,网络上有很详细的介绍.这里只做简单介绍. 需要的安装包一共有两个:Qt Creator 和QTE. 1)QT Creator 下载地址:qt-sdk-linux ...
- windows关闭进程 批处理端口占用
cmd 关闭进程java taskkill /F /IM java.exe taskkill /f /im java.exe 如何用dat批处理文件关闭某端口对应程序-Windows自动化命令 如何用 ...
- C++开发人脸性别识别教程(10)——加入图片的人脸检測程序
现在我们的MFC框架已经初具规模,能够读取并显示目录下的图片.在这篇博文中我们将向当中加入人脸检測的程序. 一.人脸检測算法 这里我们使用OpenCv封装的Adaboost方法来进行人脸检測,參见:C ...
- swift3.0调用相册
swift3.0调用相册首先需要注意: 1.swift3.0中调用相机和相册会导致崩溃 1.需要在info.plist文件中加入两个键值对,如下: /// 都是String类型,内容任意的字符串即可 ...
- SocketChannel API用法
java.nio.channels 类 SocketChannel java.lang.Object java.nio.channels.spi.AbstractInterruptibleChanne ...
- Android自定义组件系列【6】——进阶实践(3)
上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...
- 走进windows编程的世界-----对话框、文本框、button
1 对话框的分类 2 对话框的基本使用方式 3 对话框资源 4 有模式对话框的使用 int DialogBox( HINSTANCE hInstance, LPCTSTR lpTemplate, ...
- new File(String Path)加载资源问题
2017-12-17 15:07:38 [原创-wx] 一.我们在用IO流加载资源的时候,创建文件资源 1 File file = New File("String Path" ...
- HBase总结(十一)hbase Java API 介绍及使用演示样例
几个相关类与HBase数据模型之间的相应关系 java类 HBase数据模型 HBaseAdmin 数据库(DataBase) HBaseConfiguration HTable 表(Table) H ...
- 《学习opencv》笔记——关于一些画图的函数
画图函数 (1)直线cvLine函数 其结构 void cvLine(//画直线 CvArr* array,//画布图像 CvPoint pt1,//起始点 CvPoint pt2,//终点 CvSc ...