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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/180746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:41:30  来源:igfitidea点击:

What's the best approach to printing/reporting from WPF?

wpfprintingreporting

提问by Matt Hamilton

I have an upcoming project which will have to be able to print simple reports from its data. It'll be WPF-based, and I'm wondering which way to go.

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

I know that WPF introduces its own printing technology (based on XPS) which looks quite easy to use. However, part of me wonders whether it would just be easier to use the ReportViewer control and embed it in a Windows Forms host control, since that will give users the ability to export to a variety of formats as well as print.

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

Has anyone had any experience with printing/reporting from WPF? Which direction would you recommend?

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

采纳答案by Bob King

We had this same issue, and ended up using RDLC/ReportViewer for now. There's no native WPF reporting tool (that I know of) and RDLC is pretty simple to use, and is free. The runtime overhead for it is small (around 2Mb) but you must remember to distribute it as it isn't part of the .NET Framework.

我们遇到了同样的问题,现在最终使用了 RDLC/ReportViewer。没有本机 WPF 报告工具(据我所知),而且 RDLC 使用起来非常简单,而且是免费的。它的运行时开销很小(大约 2Mb),但您必须记住分发它,因为它不是 .NET Framework 的一部分。

回答by Ray Burns

Limitations of RDL

RDL 的限制

I originally went with RDLC/ReportViewer for printing with WPF but found it very limiting. Some of the limitations I found were:

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

  • RDL could only create the most boring of reports
  • It was much more work to create a report using RDL than in straight WPF: The design tools are very primitive compared to Expression Blend and RDL deals only in tables
  • I didn't have the ability to use ControlTemplates, DataTemplates, Styles, etc
  • My report fields and columns could not effectively resize and rearrange based on data size
  • Graphics had to be imported as images - it could not be drawn or edited as vectors
  • Positioning of items required code-behind rather than data binding
  • Lack of transforms
  • Very primitive data binding
  • RDL 只能创建最无聊的报告
  • 使用 RDL 创建报告比直接使用 WPF 需要做更多的工作:与 Expression Blend 相比,设计工具非常原始,RDL 仅处理表格
  • 我没有能力使用 ControlTemplates、DataTemplates、Styles 等
  • 我的报表字段和列无法根据数据大小有效地调整大小和重新排列
  • 图形必须作为图像导入 - 它不能作为矢量绘制或编辑
  • 定位需要代码隐藏而不是数据绑定的项目
  • 缺乏转换
  • 非常原始的数据绑定

Printing directly from WPF is very easy

直接从 WPF 打印非常容易

Because of these limitations I looked into creating reports using pure WPF and discovered it was really quite trivial. WPF allows you to implement your own DocumentPaginatorsubclass that can generate pages.

由于这些限制,我研究了使用纯 WPF 创建报告并发现它真的很简单。WPF 允许您实现自己的DocumentPaginator可以生成页面的子类。

I developed a simple DocumentPaginator subclass that takes any Visual, analyzes the visual tree, and hides selected elements to create each page.

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

DocumentPaginator details

文档分页器详细信息

Here is what my DocumentPaginator subclass does during initialization (called when first PageCount is fetched, or during the first GetPage() call):

这是我的 DocumentPaginator 子类在初始化期间所做的事情(在获取第一个 PageCount 时或在第一个 GetPage() 调用期间调用):

  1. Scans the visual tree and makes a map of all scrolled panels inside ItemsControls
  2. Starting with the outermost, makes items in the ItemsControls invisible last to first until the Visual fits on a single page without any need to scroll. If the outermost can't be reduced enough, reduces inner panels until it succeeds or has only one item at each level. Record the set of visible items as the first page.
  3. Hide the lowest-level items that have already been shown on the first page, then make subsequent items visible until they no longer fit on the page. Record all but the last-added item as the second page.
  4. Repeat the process for all pages, storing the results in a data structure.
  1. 扫描可视化树并制作 ItemsControls 内所有滚动面板的地图
  2. 从最外面开始,使 ItemsControls 中的项目从后到先不可见,直到 Visual 适合单个页面而无需滚动。如果最外层不能减少足够,减少内面板直到它成功或每个级别只有一个项目。将可见项集记录为第一页。
  3. 隐藏已在第一页上显示的最低级别的项目,然后使后续项目可见,直到它们不再适合该页面。将除最后添加的项目以外的所有项目记录为第二页。
  4. 对所有页面重复该过程,将结果存储在数据结构中。

My DocumentPaginator's GetPage method is as follows:

我的 DocumentPaginator 的 GetPage 方法如下:

  1. Look up the given page number in the data structure generated during initialization
  2. Hide and show items in the visual tree as indicated in the data structure
  3. Set PageNumber and NumberOfPages attached properties so report can display page numbering
  4. Flush the Dispatcher (Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => {} ));) to get any background rendering tasks to complete
  5. Create a Rectangle the size of the page whose VisualBrush is the visual being printed
  6. Measure, Arrange, and UpdateLayout the rectangle, then return it
  1. 在初始化期间生成的数据结构中查找给定的页码
  2. 隐藏和显示可视化树中的项目,如数据结构中所示
  3. 设置 PageNumber 和 NumberOfPages 附加属性,以便报表可以显示页码
  4. 刷新 Dispatcher ( Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => {} ));) 以完成任何后台渲染任务
  5. 创建一个与页面大小相同的矩形,其 VisualBrush 是正在打印的视觉对象
  6. 测量、排列和更新布局矩形,然后返回它

This turned out to be quite simple code, and allowed me to turn practically anything I could create with WPF into pages and print it.

结果证明这是非常简单的代码,并且允许我将几乎可以使用 WPF 创建的任何内容转换为页面并打印出来。

Additional reporting support

额外的报告支持

Now that my paginator is working, I no longer have to worry very much about whether I am creating my WPF content for screen or paper. In fact, often UI that I build for data entry and editing also works very well for printing.

现在我的分页器正在工作,我不再需要非常担心我是为屏幕还是纸张创建 WPF 内容。事实上,我为数据输入和编辑而构建的 UI 通常也适用于打印。

From there I added a simple toolbar and some code behind, resulting in a full-fledged reporting system built around WPF that was far more capable than RDL. My reporting code can export to files, print to the printer, cut/paste page images, and cut/paste data for Excel. I can also switch any of my UI to "print view" with a click of a checkbox to see what it will look like if printed. All this in just a few hundred lines of C# and XAML!

从那里我添加了一个简单的工具栏和一些背后的代码,从而产生了一个围绕 WPF 构建的成熟的报告系统,它比 RDL 功能强大得多。我的报告代码可以导出到文件、打印到打印机、剪切/粘贴页面图像以及剪切/粘贴 Excel 数据。我还可以通过单击复选框将我的任何 UI 切换到“打印视图”,以查看打印后的外观。所有这一切都在几百行 C# 和 XAML 中!

At this point I think the only feature RDL has that my reporting code doesn't have is the ability to generate a formatted Excel spreadsheet. I can see how this could be done but so far there has been no need - cutting and pasting the data alone has been enough.

在这一点上,我认为 RDL 的唯一功能是我的报告代码没有的功能是能够生成格式化的 Excel 电子表格。我可以看到如何做到这一点,但到目前为止还没有必要 - 仅剪切和粘贴数据就足够了。

From my experience my recommendation would be to write a paginator, then start using WPF itself to create your reports.

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

回答by LiamV

How about Scryber? It allows PDF report templates to be defined using xml and bound to data within your application at run time. http://scryber.codeplex.com/

斯克里伯呢?它允许使用 xml 定义 PDF 报告模板并在运行时绑定到应用程序中的数据。http://scryber.codeplex.com/

回答by VahidN

Take a look at PdfReports. It's a code first reporting engine, which is built on top of the iTextSharp and EPPlus libraries. It's compatible with both .NET 3.5+ Web and Windows applications.

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

回答by Alex Hope O'Connor

To elaborate on Ray Burns answer, if you are looking for an implementation example, see: Custom Data Grid Document Paginator

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

Which is a great starting point.

这是一个很好的起点。

回答by MoreThanChaos

I've reccently accomplished task of developing own reporting system, which basically consist on design enviroment and data Source manager. The first task was to develop WYSWIG-like design enviroment. I've done this using GDI+, without even bothering about printing, as it came out printing/generating print preview was easiest than i expected, In general it only takes to draw all things on screen to graphics object of printing event.

我最近完成了开发自己的报告系统的任务,主要包括设计环境和数据源管理器。第一个任务是开发类似 WYSWIG 的设计环境。我已经使用 GDI+ 完成了这项工作,甚至没有考虑打印,因为打印/生成打印预览比我预期的要简单,通常只需将屏幕上的所有内容绘制到打印事件的图形对象即可。

I think that in case of WPF it would be similar, so all you should worry about is to display you report on screen and printing would be only few lines of code.

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

回答by Doug

Without getting into a whole political discussion about the future of WPF, the best option we found was to wrap the ReportViewer in a Windows Forms host control.

无需就 WPF 的未来进行全面的讨论,我们发现的最佳选择是将 ReportViewer 包装在 Windows 窗体主机控件中。

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

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