用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 ...
随机推荐
- WIFI 状态栏显示的wifi信号强度与wifisetting列表不一致
[DESCRIPTION] 状态栏显示的wifi信号强度与wifisetting列表不一致(不同步) [ANALYSIS] 1.apk都是接收RSSI_CHANGED intent,并调用WifiMa ...
- Your algorithm's runtime complexity must be in the order of O(log n).
Given a sorted array of integers, find the starting and ending position of a given target value. You ...
- html5 在移动端的缩放控制
viewport 语法介绍: 01 <!-- html document --> 02 <meta name="viewport" 03 content= ...
- js实现金额小写转大写
function convertCurrency(currencyDigits) { var MAXIMUM_NUMBER = 1000000000000.00; var CN_ZERO = &quo ...
- Android TextView,EditText要求固定行数自动调整TextSize
最近项目有个需求要求文本最多显示3行,继续输入则字体变小,删除已经输入的文字,那么字体变大,不管变大变小都不能超过3行.网上怎么找也找不到相关的解决方案,自己动手,丰衣足食了! 说一下算法思路,后面给 ...
- 【hdu 1067】Gap
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission( ...
- php实现 明明的随机数
php实现 明明的随机数 一.总结 一句话总结: 1.asort是干嘛的? asort — 对数组进行排序并保持索引关系 2.从控制台取数据怎么取? trim(fgets(STDIN)) 3.多组测试 ...
- CSS盒子模型中距离的通俗解释
设一个有两个div,一大一小,小的div在大的div里面,而小的div和大div直接的距离就叫外边距,用margin.margin-left.margin-right.margin-top.margi ...
- SQLite编码
•SQLite编码 •讲师:李明杰 •技术博客:http://www.cnblogs.com/mjios •SQLite3 •在iOS中使用SQLite3,首先要添加库文件libsqlite3.dyl ...
- JVM源码分析之System.currentTimeMillis及nanoTime原理详解
JDK7和JDK8下的System.nanoTime()输出完全不一样,而且差距还非常大,是不是两个版本里的实现不一样,之前我也没注意过这个细节,觉得非常奇怪,于是自己也在本地mac机器上马上测试了一 ...