Another DataGridView Printer
Introduction
Background
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 (in addition to adding the source file to your project) you will only need to add a "using DGVPrinter" to your code file, and create an instance of the object.
//
// The using block statement
//
using DGVPrinterHelper;
For example, if you wanted to print a DataGridView when your user clicks a Print button on the toolbar, your code might look something like this:
//
// Printing from the DataGridView datagridviewControl in response to a toolbar button
// press
//
private void printToolStripButton_Click(object sender, EventArgs e)
{
DGVPrinter printer = new DGVPrinter();
printer.Title = "DataGridView Report";
printer.SubTitle = "An Easy to Use DataGridView Printing Object";
printer.SubTitleFormatFlags = StringFormatFlags.LineLimit |
StringFormatFlags.NoClip;
printer.PageNumbers = true;
printer.PageNumberInHeader = false;
printer.PorportionalColumns = true;
printer.HeaderCellAlignment = StringAlignment.Near;
printer.Footer = "Your Company Name Here";
printer.FooterSpacing = 15;
printer.PrintDataGridView(datagridviewControl);
}
At its simplest, you can just create an instance of the class and call the print or print preview methods. The user will be presented with a PrintDialog and at that point they can select the printer, and choose either 'All', 'Some' or 'Selection' to identify what portion of the input DataGridView they wish to print. The DGVPrinter respects the selection in the source DataGridView and can print row, column and cell selections.
Properties manage much of the presentation, and allow you to set the Title and Subtitle, and footer text. The page number can be configured for the right or left side of the page, and whether or not it should print on it's own line. While the settings in the DataGridView control are (fairly faithfully) reproduced by DGVPrinter, there are a number of settings that can be overridden via the properties. See the Properties section for a complete listing of what can be set.
Change from Previous Versions!
Column widths can be overridden using the "ColumnWidths" property. This property returns a Dictionary<string, float> where you can set fixed column width values. The string in the dictionary should contain column name, so that ColumnWidths[columname] is the width of that column. This allows you to set column widths prior to printing, as the print process may or may not include a specific column. As an example:
//
// Override the width of the description column only.
//
print.ColumnWidths.Add("descriptionGridViewTextBox", 200);
End Change from Previous Versions
The porportional columns setting is sensitive to the overridden column widths and will stretch the remaining columns to fill the page.
A new feature has been added to allow you to bias the printout to the right, left or center of the page. The property "TableAlignment" will shift the entire table as indicated.
//
// Center the table on the printed page
//
print.TableAlignment = DGVPrinter.Alignment.Center;
The latest update will allow printing on multiple pages when the width of the columns being printed is wider than one page. The print settings (Table Alignment, Porportional Columns, etc.) are respected for each "set" of pages printed. If a single column is wider than the page print width, it will be printed on it's own page and truncated to the width of the page. If a column is wider than the fixed width from setting a specific column width (or is wider than the width of the page) change the CellFormatFlags property to turn on wrapping (i.e. exclude the NoWrap flag) to allow the row to grow down the page:
//
// Allow multiline printing for individual cells
//
print.CellFormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoClip;
Page Numbering and Margins
A new pair of properties has been added to allow you to include the total pages when you are printing the page number. The default format is "Page n of nn". The property ShowTotalPageNumber controls this and is set to true by default. The value of the separator can be changed via the PageSeparator property. The default separator is the english " of ".
Also, the page margin handling has been tightened up so that you're less likely to run into problems with printing outside of the area your printer can handle.
Titles and Cell Formatting
All of the various sections that have string formatting associated with them (title, subtitle, pagenumber, footer, headercell and cell) all have been changed to allow access to the underlying StringFormat objects. This expands the level of control you now have over the printing of these items. The old xxxxAlignment and xxxxFormatFlags properties still exist, but are now deprecated and may be removed at a later date.
The headercell and data cell printing now respects not only the left-right bias, but also the top-bottom settings in the DataGridView. These can also be overridden by accessing the respective format objects. Note, though that these two are not available as properties, since the underlying DataGridView is necessary for setting these values. The GetCellFormat sets the default format for all the cells in the printout. Per-column formatting is now available as well through the ColumnStyles property. The order of precendence is that the per-column formatting (ColumnStyles) have the highest precedence, then column or cell styles set in the gridview, then global print settings made through GetCellFormat, and finally the default cell style from the gridview. The following example sets all cells to right justified (Alignment = StringAlignment.Far) and at the bottom of the cell (LineAlignment=StringAlignment.Far), but the second column is centered top-to-bottom and left-to-right, and printed in 12.5 point Arial:
print = new DGVPrinter();
// set the default cell printing to be bottom right.
print.GetCellFormat(gridview).Alignment = StringAlignment.Far // right justify
print.GetCellFormat(gridview).LineAlignment = StringAlignment.Far; // print at bottom of cell
// override the second column to be centered. Note the use of Clone()!
print.ColumnStyles[gridview.Columns[1].Name] = gridview.DefaultCellStyle.Clone();
print.ColumnStyles[gridview.Columns[1].Name].Font = new Font("Arial", (float)12.5);
print.ColumnStyles[gridview.Columns[1].Name].Alignment = DataGridViewContentAlignment.MiddleCenter;
The "LineAlignment" property of the StringFormat object is used to move the cell's print from top to bottom. "Near" is the same as 'Top', so if you have a DataGridViewCellStyle of "BottomLeft", the same formatting is done by setting the cell format Alignment property to Far and the LineAlignment property to Far. Note the use of Clone() when copying the cell style! This is important, otherwise any changes you make to the style for the printout will also be applied to your gridview!
Finally, headercell printing has the NoWrap format flag turned off by default, and will wrap a long cell title rather than truncating it.
Points of Interest
There are now two styles of interacting with the DGVPrinter object for printing. The original choices for starting the printing: PrintDataGridView(datagridviewControl)
and PrintPreviewDataGridView(datagridviewControl)
remain in place and fully supported. For more granular support, three new methods have been added. These methods essentially break up the two step process (print dialog, then output) in PrintDataGridView and PrintPreviewDataGridView. The new functions allow the caller to display the print dialog independantly of the actual printing process, and to possibly replace the built-in print dialog function with their own application provided functions. The goal of these changes is to increase the flexibility of the DGVPrinter object in integrating into applications. Here's an example of using the new interface:
//
// Printing from the DataGridView datagridviewControl in response to a toolbar button
// press
//
private void printToolStripButton_Click(object sender, EventArgs e)
{
DGVPrinter printer = new DGVPrinter();
printer.Title = "DataGridView Report";
printer.SubTitle = "An Easy to Use DataGridView Printing Object";
printer.SubTitleFormatFlags = StringFormatFlags.LineLimit |
StringFormatFlags.NoClip;
printer.PageNumbers = true;
printer.PageNumberInHeader = false;
printer.PorportionalColumns = true;
printer.HeaderCellAlignment = StringAlignment.Near;
printer.Footer = "Your Company Name Here";
printer.FooterSpacing = 15;
// use saved settings
if (null != myprintsettings)
printer.PrintDocument.PrinterSettings = myprintsettings;
if (null != mypagesettings)
printer.PrintDocument.DefaultPageSettings = mypagesettings;
if (DialogResult.OK == printer.DisplayPrintDialog())
{
// save users' settings
myprintsettings = printer.PrinterSettings;
mypagesettings = printer.PageSettings;
// print without displaying the printdialog
printer.PrintNoDisplay(datagridviewControl);
}
}
Both the Print and Print Preview are supported through the new interface style
The print preview uses the built in .Net PrintPreviewDialog to show a preview of what will be sent to the printer.
The DGVPrinter object is controlled through a series of properties that affect the printing. In general, the DGVPrinter uses the style settings from the source DataGridView so that what is printed will look as much like the source as is possible.
And finally, the code for the DGVPrinter object: