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

not sure what's going on there - I used the "Email" reply option. I've sent you a direct email using the email address I last had for you (2nd March 2012) - let me know if you've changed it since then!

Thank you very much for such a SIMPLE and EASY article for printing GRIDVIEW....
I was searching for this very desperately, but all I found very complex codes, I used them, but there were some part of code snippet unexplained, making it hard to use.

First, Let me say that I'm sure that this is the best DataGridView Printer ever made.
I just need some help concerning drawing text inside headers with a 270 angle. Apparently I'm not able to subscribe to the OwnerDraw event. What does this mean? print.OwnerDraw += new CellOwnerDrawEventHandler(print_OwnerDraw). Is there anything missing?

First, my apologies for not responding sooner - I've just discovered that some of the post emails from CodeProject are going into my junk folder!

To answer your question, the statement you list there registers a handler for the OwnerDraw event. The argument "print_OwnerDraw" is actually the name of a procedure that will get called when the OwnerDraw event is triggered. You write this routine. The code in this routine is your opportunity to do what you need to to handle the OwnerDraw event. I'd strongly suggest you search the internet for help on handling events - there's lots of examples out there to help you wire up the event handler properly.

I have 3 suggestion.
1. can u add some custom row in a doc end? for display the total price, percentage as well as some tips. before i think add this to DataGridView and print, but when print is finish , i should clear that row. if i can add multiple DataGridView, and you combine this ? , it's so easy for me.

2.is there any way can let the column width automatically populated? if i'm use

DGVPrinter.ColumnWidthSetting.CellWidth

or

DGVPrinter.ColumnWidthSetting.Porportional

Its width may exceed the page, if i'm use

ColumnWidthSetting.DataWidth

It will be remaining lot of space. can u just let It automatically calculates the width to fit the page? (Beyond the automatic line feed)?

3.if i'm print , i only can print vertical mode on A4. can i choise the print mode like horizontal?

When the datagridview is wider than a printed page and the RowHeight setting is CellHeight then printing is fine irrespective of 'porportional' setting.
But when RowHeight is set to DataHeight then the height of the rows seems to depend upon the largest text string within that row even though the text is not wrapped.
regards ron.

further to the problem above
the problem seems to be the connection between AdjustPageSets and RecalcRowHeights. the routine AdjustPagesets is entered with a pageset which calls RecalcRowHeights with the number of columns within that pageset. On further pagesets RecalcRowHeights starts off looking at columns within the first pageset and because the column widths are different the heights of the rows are adjusted even though data in cells is not wrapped.

In the routine calccellsize after the else statement I put in a mod because a checkboxcell returns an invalid height when g.MeasureString(String,Font,Size,format) is used, at least it does on my system.

I have a dgv that contains some ID's that I do not want to be showed, so in the dgv properties, where you edit the columns, the first column's ID property "visible" I set it to "false", so when I print, the header is missing...

to fix that I moved to the last column this invisible column ID and then the printer could show the header of dgv