Introduction

I went looking for a class to do printing from a DataGridView, and none of them did all that I was looking for. I needed to print all pages, some pages, or the current selection; and I needed to not have objects, controls, or code from the printer object sprinkled through the rest of my code - i.e., it needed to be completely self-contained. Nothing I found met all those requirements, so I ended up writing my own.

Using the Code

To use the DGVPrinter class, you have two options. First, you can simply add the DGVPrinter.cs source file to your project, or second you can place the DLL in your "Bin" directory and add a reference to the DGVPrinter.dll to your project's references. In either case, to use the DGVPrinter, you will only need to add a "using DGVPrinter" to your code file, and create an instance of the object.

The basic interface used here provides a neat, one-stop-shop for printing a DataGridView. But, what if you want to have more control over the printing process? Say you'd like to save your users' print preferences or provide a default printer? To help you with this, DGVPrinter provides a more complex interface. Here's an example where the calling program provides overrides to the PrinterSettings and the DefaultPageSettings:

DGVPrinter's various settings provide good control of all aspects of printing on the page. You can set the Title and Subtitles, add a footer, and control whether the page number prints in the header or footer. DGVPrinter supports Right-to-Left printing for non-Western languages and includes a drawing override for situations where a cell or column has onPaint overridden in the source DataGridView control. While the default styles for the printed DataGridView are taken from the source DataGridView control, DGVPrinter also provides many attributes that allow you to control the styling of almost every aspect of the printout.

History

Version 1.0 - Initial publication

Version 1.1 - Added footer handling, and allows the page number to print in the header or footer, and if it should print on the same line as the header or footer

Version 1.4 - Added support for printing directly to a provided Graphics object

Version 2.0 - Added support for printing images on the page

Version 3.0 - Breaking changes! Please read!

Added support for cells/rows that span more than one page of depth. If a cell would run off the bottom of the page, the "KeepRowsTogether" property determines if a partial row is printed or a new page is started.

Added support for Setting the styles for Row and Column Headers. The properties for setting Header cell styles changed names, and the return type of "PrintColumnHeaders" changed. This can cause your program to not compile/run!

Added a default value so row headers will show up if they are supposed to be "visible"

Added title and subtitle spacers. These will help give you control of the whitespace below the Title and Subtitle.

Compiled version for VB and other language support

Version 3.1 - Fix cell background color printing

Version 3.2 - Fixes for Embedded Print function

Version 3.3 - Unlikely but possible breaking change

Add Delegate to allow "Owner Drawing" of cells, including row and column headers

Add better support for cell size, data size or proportional scaling of columns. The identifier 'StringHeight' has been changed to 'DataHeight' since the size of an image is now properly accounted for. This may break your code if you depend on this feature.

Bug Fixes

Version 3.4 - Add support for Alternating Rows when ColumnStyles are overridden

Version 3.5 - More fixes for Alternating Rows ColumnStyles

Version 3.6 - Fix for Imbedded Image drawing; images now draw at original pixel sizes without scaling

I have a problem when AutoSizeMode=Fill is set to a column and want the DataGridView to be printed into one page, filling the paper's width. ProportionalColumns=True and ColumnWidth = Proportional does not work. It breaks into a new page after this column. I tried setting other columns' AutoSizeMode value to None and NotSet. Same output.

It only happens in Portrait Mode. In Landscape Mode works fine.
There are 3 columns with widths of 100, 300 (AutoSizeMode=Fill), 100.

DGVPrinter pays no attention to the column property "AutoSizeMode", so I'm sure that has little to do with what's happening. In my testing, If I set the first and last column widths, and set PorportionalColumns to True, I get what I think you're aiming for: two smaller columns with the center column filling the page. Here's the relevant code:

Is there any way to print fixed width columns as they are and the fill column to adapt its width to the rest of the printable width?

I tried some samples and if total columns width are greater than paper width, it prints several pages, but the fill column is almost empty as it is only for design on a form for fully fill the width if resized (maximizing the datagridview).

The sample code above does what you're looking for, on my test system. Granted, that's a big caveat, but it should work for you. Setting "PorportionalColumns" to true tells DGVPrinter to spread all columns accross the page width porportionally. Next, setting individual column widths to specific values tells DGVPrinter to override the column width calcs and just use these fixed widths. In a 3 column print, setting the first and last columns to fixed widths leaves all the "flex" in just the one center column.

The trick is to tell the DGVPrinter object specifically which columns to set to fixed widths; you can't depend on the DataGridView column properties for this to work.

In the example you put i your project you put an example to insert an image.
I'am using your DGV in Visual Basic but can't get it to print an image.
All works (Title, subtitle, margins, foot, pages, etc.)nice except that I can't put "print.ImbeddedImageList.Add(ii1);"
¿Could you please give me the code to print the image in Visual Basic?

When I print the grid the end of the content gets cut off on the actual printed page. The printout looks perfect in the Print preview but when I send it to OneNote or any of 3 different printers I have tried the end of all the columns are cutoff and the page numbers look like this "Pa" Instead of "Page 1 - Part 1".

I tried setting margins to all 0 just to see what it would change and even with them all set to 0 in landscape the end is still cut off. I would provide some screen shots but I cant here.

I do have a logo printing in the page and have even tried removing it completely and it still cuts off the end of all columns and page numbers.

I don't have any special settings it basically using the code from the example other than I have tried setting the margins in code and also let it use the default margins.

I've tried this on the few printers that I have access to and cannot reproduce your problem. What I suspect is that the page size and margins being reported by the printer driver do not match the actual page size and margins on the printer.

Normally I would agree with that but I have tried it on 4 different printers now and MS OneNote and get the same result from all of them. 3 printers here at work and 1 at home. Below is the code I am using. Do you see anything that might cause the issue? As far as the margins I have set below I have tried it with the default margins and it did the same thing that's why I was playing with the margins in the code below.

I do notice one thing is that if I leave the margins at default and print to Portrait it appears to print perfectly, but with them at default and printing to landscape it still cuts off all the ends of the columns in the grid and the page numbers. And in landscape it appears to be putting a big margin on the left side of the page even though there is not one set anywhere.

I have been doing a little testing and I have found out that if I first print to a windows XPS document then open that it looks perfect and then I select print from there and send to one note and it looks perfect. But then from the XPS if I select print and send it to the printer the ends are cut off again.

Which is why I suspect that the printer driver is either not accurately reporting the actual margins. But, there's still the possibility that DGVPrinter is mis-interpreting what the printer driver is telling it, which is why I'd like to look at the log.

Nothing sent through CodeProject email seems to have arrived at either end; however, I did get the log file you sent directly. It looks like DGPrinter is working OK. The printer driver reports hard margins of 25 and 20 with a total page width of 1100; DGVPrinter ends up using 42 and 40, with a print width of 1017 to space out the grid, which means everything should print OK. Since 42+42+1017 = 1101, the printed grid should fit OK within the page size of 1100 (the extra one is rounding error). Nothing here indicates that the print would be biased to the right and the right most bits cut off.

One thing you can try is narrowing the margins you provide to try to force the grid into a narrower profile to fit within the actual print area rather than the reported print area.

I'll look at this some more in the next day or so and let you know if I find anything, but from what you've reported (especially about printing from an XPS document) it sounds like the printer and printer driver are not on the same page.

Ok thanks for checking it out. One of the strange things I noticed is that when printing especially in landscape even though I have the margins set at 10,10,40,40 there always seems to be a large margin on the left of the page that looks to be about a 1 inch margin. I tried it from my printer at home last night and even on that printer it does the same thing, looks perfect in the print preview in landscape but when it comes out on paper its all pushed to the right.

Strange thing is I have other code that I wrote that basically uses system.printing and GDI drawing that prints perfectly from this same app and was attempting to replace it with the DGVPrinter mainly because it has way more options than my basic printing function. I'm pretty sure its something in the DGVPrinter that I am either somehow using bad configuration or something about my grid that is throwing it off, although like I said I have some pretty basic printing code in my app that prints the same grid to a physical printer or to one note with out any issues at all.

I will continue to trying and figure out whats going on and if I have any new information I will post it here.