0 Comments

If you’re writing line of business software of almost any description, you probably need to generate reports.

In the industry that I’m current working in, these reports are typically financial, showing the movement of money relating to a trust account.

Our legacy product has been around for a very very long time, so it has all the reports you could need. Unfortunately, they are generated using an ancient version of crystal reports, which I’m pretty sure is possessed by a demonic entity, so they can be a bit of a nightmare to maintain.

For our new cloud product, I’m not entirely familiar with how we deal with reports, but I think that they are generated using HTML and then converted to PDF. Its enough of a feature that there’s a whole reporting subsystem dedicated to the task).

Unfortunately, our most recent development efforts in the legacy product fall somewhere in the middle between terrifying ancient evil and relatively modern report generation processes.

The crystal reports component is VB6 native, and all of our new functionality is written in C# (using WPF for the view layer). We could call back into the VB6 to generate a report, but honestly, I don’t want to touch that with a ten-foot pole. We can’t easily leverage the HTML/PDF generation capabilities of the new cloud product either, as it was never built to be reused by an entirely different domain.

As a result, we’ve mostly just shied away from doing reports as a part of new features.

Our latest feature is a little different though, as it is an automated receipting solution, and a report of some description is no longer optional.

Last responsible moment and all that.

Forming An Opinion

If you’re trying to build out a report in WPF, you’d think that there would be a component there all ready to go.

You’d be mostly wrong, at least as far as native WPF is concerned. There are a few bits and pieces around, but nothing particularly concrete or well put together (at least as far as we could determine anyway).

Instead, most people recommend that you use the Windows Forms Report Viewer, and the systems that it is built on.

We poked at this for a little while, but it just seemed so…archaic and over complicated. All we wanted was to take a View Model describing the report (of our design) and Bind it, just like we would for a normal WPF view.

Enter the FlowDocument.

In The Flow

I’ll be honest, I didn’t actually do the work to build a report out in WPF using FlowDocuments, so most of what I’m writing here is second hand knowledge. I didn’t have to live through the pain, but the colleague that did it assures me that it was quite an ordeal.

At their core, FlowDocuments allow you to essentially create a document (like a newspaper article or something similar) in WPF. They handle things like sizing the content to the available area, scrolling and whatnot, all with the capability to render normal XAML controls alongside textual constructs (paragraphs, images, etc).

There are a few things that they don’t do out of the box though:

  • Pagination when printing. The default paginator is mostly concerned with making pages for a screen (rather than a printed document), and doesn’t allow for headers or footers at all. As a result, we implemented a custom DocumentPaginator that did what we needed it to do.
  • Templated content repetition. If you’re using WPF, and MVVM, you’re probably familiar with the ItemsControl (or its equivalents). If you want to do something similar in a FlowDocument though (i.e. bind to a list of things), you’ll need to put together a custom templating system. This is relevant to us because our report is mostly tabular, so we just wanted a relatively simple repeater.

With those bits and pieces out of the way though, what you get is a decent component that you can use on top of a view model that displays the report to the user in the application (i.e. scrolling, text selection, etc) with the capability to print it out to any of the printers they have available.

Its not exactly a ground breaking advance in the high-tech field of report generation, but it gets the job done without any heavyweight components or painful integrations.

Conclusion

I’m sure there are hardcore reporting components out there that are built in pure WPF and do exactly what we want, but we just couldn’t find them.

Instead, we settled for knocking together some extensions to the existing FlowDocument functionality that accomplished exactly what we needed and no more.

With a little bit of effort, we could probably make them more generic and reusable, and I might even look into doing that at some point in the future, but to be honest now that we’ve done the one report that we needed to do, we’ll probably mostly forget about it.

Until the next time of course, then we’ll probably wonder why we didn’t make it generic and reusable in the first place.