72

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.

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.

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

Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320
  • [SimpleWPFReporting](https://github.com/maximcus/SimpleWPFReporting) gives you the ability to create any report with the full power of WPF XAML. SimpleWPFReporting will take care of exporting it as a PDF or printing it. – Max Mar 24 '17 at 06:05

8 Answers8

43

Limitations of RDL

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

  • 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

Printing directly from WPF is very easy

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 DocumentPaginator subclass that can generate pages.

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

DocumentPaginator details

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

  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.

My DocumentPaginator's GetPage method is as follows:

  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

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.

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.

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!

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.

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

Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • 7
    Very interesting as I'm thinking of dropping RDLC. Have you published any of the code of your document paginator? – Eduardo Molteni Jan 03 '11 at 18:32
  • 2
    Could you expand on this at all? Perhaps with some short code/xaml examples? – Alex Hope O'Connor Nov 08 '12 at 01:25
  • 1
    Found this: http://www.codeproject.com/Articles/138233/Custom-Data-Grid-Document-Paginator – Alex Hope O'Connor Dec 07 '12 at 00:23
  • This solution of yours is a perfectly fit candidate for OpenSourcing, which could be something that would bring back benefits to yourself and your company (at the cost of some extra initial work, we know...) – heltonbiker Jan 11 '13 at 14:59
  • 7
    "Printing directly from WPF is very easy". Is it really? I've already put a lot of time and effort into implementing this and paginating a databound datagrid is not easy by any stretch of the imagination. I'm afraid the devil's in the details and until I see some, this answer is not very useful. – Manos Dilaverakis Feb 21 '13 at 19:40
  • @RayBurns would you like to share your code (just the part with the visibility would be enough)? I have a bounty on a [Question](http://stackoverflow.com/questions/3892054/documentpaginator-that-works-with-any-visual) where your answer would fit very well – WiiMaxx Feb 03 '14 at 13:58
  • 1
    Here, here, @RayBurns. Let's see a github repo so we can help contribute to this awesome-sounding implementation. – Killnine Mar 25 '14 at 13:07
  • 1
    Interesting, but it has been 6 years from the answer, still couldn't find any `class` that help me to convert `xaml` view to page. Also, there is no other way :( – Gopichandar Jun 02 '16 at 14:02
  • I have taken a similar approach to this but instead of messing around with the visual tree I use a view model that has `Items` and `CurrentPageItems` where items are added until the page overflows then removes one item. The view model approach lets you do things like get page subtotals very easily and can have additional properties like IsLastPage which you can use to toggle a footer and such, making it very powerful. I will probably write some blog posts about this and post some code in the near future but that's the general approach I would suggest if you are thinking of doing this – Mike Marynowski Dec 03 '17 at 17:35
  • It's definitely not an easy task. I also tried to do this, but there are so many things to build that you ussually end up dropping everything. Styling DocumentViewer, code for exporting to pdf/excel/Word, building custom paginator... Just a few, not to mention dynamic values, grouping data, repeating elements like table header etc.... Hard and long work! – Lucy82 Apr 16 '20 at 08:41
25

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.

Bob King
  • 25,372
  • 6
  • 54
  • 66
8

Look at http://wpfreports.codeplex.com/

Lukas Cenovsky
  • 5,476
  • 2
  • 31
  • 39
  • i found an [artikel](http://www.nullskull.com/a/1426/wpf-report-engine-part-1.aspx) on nullskull which explains step by step how to create a WPF Report Engine using the same approach. – WiiMaxx Aug 26 '14 at 09:52
  • Looks nice, but on 2020/11/11 project description still says "This is a very early alpha version not intented to be used in production environments." – UяošKoт Nov 11 '20 at 14:57
3

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.

VahidN
  • 18,457
  • 8
  • 73
  • 117
3

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/

LiamV
  • 1,138
  • 1
  • 14
  • 21
2

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

Which is a great starting point.

Alex Hope O'Connor
  • 9,354
  • 22
  • 69
  • 112
1

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.

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.

MoreThanChaos
  • 2,054
  • 5
  • 20
  • 40
0

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.

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

Doug
  • 37
  • 4