从 WPF 打印/报告的最佳方法是什么?

我有一个即将到来的项目,将必须能够打印简单的报告从其数据。它将是基于 WPF 的,我不知道该走哪条路。

我知道 WPF 引入了自己的打印技术(基于 XPS) ,看起来很容易使用。然而,我有点怀疑使用 ReportViewer 控件并将其嵌入 Windows 窗体宿主控件是否会更容易,因为这将使用户能够导出到各种格式以及打印。

有人有从 WPF 打印/报告的经验吗? 你会推荐哪个方向?

50557 次浏览

最近完成了开发自己的报表系统的任务,该系统主要由设计环境和数据源管理器组成。第一个任务是开发类似 WYSWIG 的设计环境。我使用 GDI + 完成了这项工作,甚至没有考虑打印,因为打印/生成打印预览比我预期的要容易,一般来说,它只需要把屏幕上的所有东西绘制到打印事件的图形对象。

我认为在 WPF 的情况下,它会是类似的,所以你应该担心的是显示你的报告在屏幕上和打印将只有几行代码。

我们遇到了同样的问题,目前只能使用 RDLC/ReportViewer。没有原生的 WPF 报告工具(据我所知) ,RDLC 使用起来非常简单,而且是免费的。它的运行时开销很小(大约2Mb) ,但是必须记住分发它,因为它不属于。NET 架构。

RDL 的局限性

我最初使用 RDLC/ReportViewer 打印 WPF,但发现它非常有限。我发现的一些局限性是:

  • RDL 只能创建最无聊的报告
  • 使用 RDL 创建报告比直接使用 WPF 要费力得多: 与 Expression Blend 和 RDL 仅处理表相比,设计工具非常原始
  • 我没有能力使用 ControlTemplate、 DataTemplate、 Styles 等
  • 我的报表字段和列无法根据数据大小有效地调整大小和重新排列
  • 图形必须作为图像导入-它不能作为矢量绘制或编辑
  • 项的定位需要代码隐藏而不是数据绑定
  • 缺乏变形
  • 非常原始的数据绑定

直接从 WPF 打印是非常容易的

由于这些限制,我研究了使用纯 WPF 创建报告,发现它实际上非常琐碎。WPF 允许您实现自己的可以生成页面的 DocumentPaginator子类。

我开发了一个简单的 DocumentPaginator 子类,它接受任何 Visual,分析可视化树,并隐藏所选元素以创建每个页面。

DocumentPaginator 详细信息

下面是我的 DocumentPaginator 子类在初始化期间(在获取第一个 PageCount 时调用,或在第一个 GetPage ()调用期间调用)所做的工作:

  1. 扫描视觉树并绘制 ItemsControls 中所有滚动面板的映射
  2. 从最外层开始,使 ItemsControls 中的项从最后到最先不可见,直到 Visual 适合单个页面,而不需要滚动。如果最外面的面板不能减少到足够的程度,减少内部面板,直到它成功或者在每个级别只有一个项目。将可见项目集记录为第一页。
  3. 隐藏已经显示在第一页上的最低级项,然后使后续项可见,直到它们不再适合该页。将除最后添加的项目外的所有内容记录为第二页。
  4. 对所有页重复该过程,并将结果存储在数据结构中。

我的 DocumentPaginator 的 GetPage 方法如下:

  1. 在初始化过程中生成的数据结构中查找给定的页码
  2. 按照数据结构中的指示隐藏和显示可视化树中的项
  3. 设置 PageNumber 和 NumberOfPages 附加属性,以便报表可以显示页码
  4. 刷新 Dispatcher (Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => {} ));)以获取要完成的任何背景呈现任务
  5. 创建一个矩形,其大小为页面的 VisualBrush 是要打印的视觉效果
  6. 测量、排列和 UpdateLayout 矩形,然后返回它

这是一个非常简单的代码,并且允许我将我能用 WPF 创建的任何实际内容转换成页面并打印出来。

额外的报告支持

现在我的分页器可以工作了,我不再需要担心是否要为屏幕或纸张创建 WPF 内容。事实上,我为数据输入和编辑构建的 UI 通常也能很好地用于打印。

在那里,我添加了一个简单的工具栏和一些代码,从而形成了一个围绕 WPF 构建的成熟的报告系统,其功能远远超过 RDL。我的报表代码可以导出到文件、打印到打印机、剪切/粘贴页面图像以及为 Excel 剪切/粘贴数据。我也可以切换任何我的用户界面“打印视图”与一个复选框点击,看看它会像什么样子,如果打印。所有这些只需要几百行 C # 和 XAML 代码!

此时,我认为 RDL 唯一没有的特性就是能够生成格式化的 Excel 电子表格。我可以看到如何做到这一点,但迄今为止还没有需要-剪切和粘贴数据本身就足够了。

根据我的经验,我的建议是编写一个分页器,然后开始使用 WPF 本身来创建您的报告。

在不讨论关于 WPF 未来的全部政治讨论的情况下,我们发现最好的选择是将 ReportViewer 封装在 Windows 窗体宿主控件中。

Http://blog.pineywoodstech.com/index.php/2012/01/using-microsoft-reportviewer-with-wpf/

看看 PdfReports。它是一个代码优先报告引擎,构建在 iTextSharp 和 EPPlus 库之上。两者兼容。NET 3.5 + Web 和 Windows 应用程序。

要详细说明 Ray Burns 的答案,如果您正在寻找一个实现示例,请参见: 自定义数据网格文档分页器

这是个很好的起点。

Scryber 怎么样?它允许使用 xml 定义 PDF 报表模板,并在运行时绑定到应用程序中的数据。http://scryber.codeplex.com/