应该说,WPF极大地简化了我们的打印输出工作,想过去使用VC++做开发的时候,打印及预览可是一件极麻烦的事情,而现在我不会再使用C++来做Windows的桌面应用了——性价比实在太低。

WPF的打印功能是很强大而简便的,它甚至能够直接打印界面上的内容,包括各种控件的显示内容,例如你在界面上摆放了一个datagrid控件,画了一个五角星,或写了一段文字,都可以直接打印出来,这里有一篇文章很简单明了地说明了这个功能:

WPF 打印实例 - Gnie - 博客园

这种做法是非常直截了当的,但恐怕不是很适合我们一般的应用,我们更多的时候需要自适应纸张,表格输出,自动分页,还有分页预览……

自己设计分页是非常麻烦的事情,没做过的人恐怕没法理解为什么,我这里插点题外话提一下,为什么分页难做?那是因为:你不真正把文档打印出来,你就不知道到底要在什么地方分页。举个最简单的例子,就一大段文本,给你打印,你认为到第几个字要另开一页?你估算了一下:一行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:

[复习].net的Invoke - guogangj - 博客园

最后,主界面上的“直接打印”为了防止用户连续点击,需要在点了一下之后把它变灰,然后过几秒钟之后再把它变亮。

最后的最后:完整代码下载

标签: WPF

用WPF实现打印及打印预览相关推荐

  1. Lodop中特殊符号¥打印设计和预览不同

    Lodop中¥符号样式改变问题 Lodop中对超文本样式的解析,虽然说是按照调用的本机ie引擎,但是调用的ie版本可能不同,导致在ie下是一种样式,预览又是另一种样式.可能是有些样式没有具体设置,走的 ...

  2. 用友T6软件设置打印模板后预览没有变化-用友T6

    设置打印模板后预览没有变化 原因分析:操作员在进行打印预览时如果在预览界面选择"保存当前设置",此时会在C盘下生成一个XML格式的文件,无论如何修改单据打印模板,预览调取的都是保存 ...

  3. 自定义模板、自定义打印机、自动打印:grid++ report自动打印、clodop预览和自动打印(electron+vue)

    一.grid++ report选择模板预览和自动打印 这里主要是前后端配合,数据前端传入,打印后端配置. IGridppReport 成员: 封装立即打印,数据格式为: {"reportDa ...

  4. 水晶报表制作6*4cm的打印纸标签,预览时数据是一页,打印出来却多了一页空白?

    欢迎来到一块钱的博客!!! 问题描述:水晶报表 预览时数据是一页,打印出来却多了一页空白.如图: 问题情况分析: 尝试1: 用水晶报表工具Crystal Reports2010设置一个(宽)6X4cm ...

  5. C#调用CodeSoft Label档打印Label及预览Demo

    一.布局如下 二.后端代码实现如下 public string str = "887451254";public string filePath=null;string labFi ...

  6. ie浏览器html打印预览,Javascript实现IE打印页面设置、预览、首页设置的代码

    1.js代码方式 复制代码 代码示例: IE打印页面设置-www.jquerycn.cn .noprint{ display:none; } function printsetup(){ // 打印页 ...

  7. PB设置打印比例和预览比例

    string ls_zoom ls_zoom = 50 //50%的比例 //预览比例 dw_1.modify("datawindow.print.preview.zoom=" + ...

  8. IE调用WebBrowser控件实现WEB打印、分页打印、无预览打印

    WebBrowser控件 WebBrowser ActiveX 控件提供托管的包装. 托管的包装便可以在 Windows 窗体客户端应用程序中显示网页. 你可以使用WebBrowser控件重复中你的应 ...

  9. Java 打印功能带预览,自定义纸张大小

    效果图 package print; import java.awt.*; import java.awt.print.*; import javax.print.PrintService; impo ...

  10. 增加了页面的打印功能以及预览功能

    弹窗部分代码 <div> <el-button type="primary" size="small" @click="previe ...

最新文章

  1. 嵌入式Linux之我行——ARM MMU工作原理剖析
  2. 绑定线程到特定CPU处理器
  3. PMCAFF | 智能硬件2.0时代:用户导向,内容连接
  4. android学习笔记(入门篇)
  5. IDEA 单元测试报错:Class not found
  6. boost::type_traits模块用法的一些示例
  7. 职场健康:缓解脖子酸
  8. MODIS NDVI数据处理相关问题
  9. 生产者消费者 java实现_Java生产者消费者的三种实现
  10. 【转】javascript判断浏览器是不是IE
  11. Ubuntu下Hadoop的安装和配置
  12. 【Foreign】字符串匹配 [KMP]
  13. 适合WhatsApp网页版的4个最好的免费WhatsApp 群发工具
  14. 原生JavaScript贪吃蛇
  15. 宝藏又小众的覆盖物PBR多通道贴图素材网站分享
  16. 面试季,覆盖70%-80%的面经基础题(java及安卓)-------网络篇
  17. MFC 多个RadioButton设为一组 vs2013
  18. [转幺幺]硬件解码—NDS影音播放专家iPlayer卡评测
  19. 前端面试题(AJAX)
  20. Windows组策略管理

热门文章

  1. cxfservlet_webService框架CXF的简单使用
  2. 微信小程序:酒桌扑克娱乐喝酒小游戏
  3. win+快捷键(常用)
  4. 【华为机试题】华为机试真题附解答(2020.9.16/c++)
  5. 关于数字化营销,这些知识点你一定要知道
  6. 计算机学院女神,女神季·计算机科学与技术学院——第六期
  7. python群控模拟安卓系统_手机群控脚本通用版安装包下载-手机群控脚本通用版apk(云控平板)v1.0.01真机模拟版_新绿资源网...
  8. win7系统服务器管理器在哪里找,win7打开服务管理器
  9. Laravel框架安装
  10. 10款超炫HTML5游戏 附游戏源码