The DataGrid is a highly versatile component of the .NET architecture and probably one of the most complex components. I wrote this article in response to the question, "How the heck do I print out a DataGrid and its contents". My first off the cuff suggestion was to capture the form using my screen capture article, but this of course does not solve the problem of printing out the umpteen rows being virtually displayed in the DataGrid. Then I thought to myself, this should be easy, I'll just use GDI+ and go through the rows in the DataGrid and print out its contents. Well the DataGrid is a bit more complex than that because it does not contain the data within itself. The data is contained within the DataSet. So the approach I settled on was to capture the color and font properties from the DataGrid for the printout, and the capture the information in the rows from the DataSet. In order to encapsulate the drawing of the DataGridPrinter to the Printer, I created the DataGridPrinter class shown in Figure 2 below. This class takes a DataGrid, a PrintDocument, and a DataTable passed to its constructor and utilizes these objects to draw the DataGrid to the printer.

Figure 1. The Print Preview of the Northwind DataGrid

Figure 2. DataGridPrinter Class UML Design (Reverse engineered using WithClass 2000)
The DataGridPrinter is constructed in the constructor of the form so it can be utilized by all of the printing functions (print, print preview, etc.) Below is the code for constructing the DataGridPrinter:
- void SetupGridPrinter()
- {
- dataGridPrinter1 =new DataGridPrinter(dataGrid1, printDocument1,
- dataSet11.Customers);
- }
- private void printDocument1_PrintPage(object sender,System.Drawing.Printing.PrintPageEventArgs e)
- {
- Graphics g = e.Graphics;
- // Draw a label title for the grid
- DrawTopLabel(g);
- // draw the datagrid using the DrawDataGrid method passing the Graphics surface
- bool more = dataGridPrinter1.DrawDataGrid(g);
- // if there are more pages, set the flag to cause the form to trigger another print page event
- if (more == true)
- {
- e.HasMorePages =true;
- dataGridPrinter1.PageNumber++;
- }
- }
- private void PrintMenu_Click(object sender, System.EventArgs e)
- {
- // Initialize the datagrid page and row properties
- dataGridPrinter1.PageNumber = 1;
- dataGridPrinter1.RowCount = 0;
- // Show the Print Dialog to set properties and print the document after ok is pressed.
- if (printDialog1.ShowDialog() == DialogResult.OK)
- {
- printDocument1.Print();
- }
- }
Now let's take a look at the internals of the DataGridPrinter methods. There are two main methods in the DataGridPrinter class that do all the drawing: DrawHeader and DrawRows. Both these methods extract information from the DataGrid and the DataTable to draw the DataGrid. Below is the method for drawing the rows of the DataGrid:
- public bool DrawRows(Graphics g)
- {
- try
- {
- int lastRowBottom = TopMargin;
- // Create an array to save the horizontal positions for drawing horizontal gridlines
- ArrayList Lines = new ArrayList();
- // form brushes based on the color properties of the DataGrid
- // These brushes will be used to draw the grid borders and cells
- SolidBrush ForeBrush = new SolidBrush(TheDataGrid.ForeColor);
- SolidBrush BackBrush = new SolidBrush(TheDataGrid.BackColor);
- SolidBrush AlternatingBackBrush = new SolidBrush
- TheDataGrid.AlternatingBackColor);
- Pen TheLinePen = new Pen(TheDataGrid.GridLineColor, 1);
- // Create a format for the cell so that the string in the cell is cut off at the end of
- the column width
- StringFormat cellformat = new StringFormat();
- cellformat.Trimming = StringTrimming.EllipsisCharacter;
- cellformat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.LineLimit;
- // calculate the column width based on the width of the printed page and the # of
- columns in the DataTable
- // Note: Column Widths can be made variable in a future program by playing with the GridColumnStyles of the
- // DataGrid
- int columnwidth = PageWidth / TheTable.Columns.Count;
- // set the initial row count, this will start at 0 for the first page, and be a different
- value for the 2nd, 3rd, 4th, etc.
- // pages.
- int initialRowCount = RowCount;
- RectangleF RowBounds = new RectangleF(0, 0, 0, 0);
- // draw the rows of the table
- for (int i = initialRowCount; i < TheTable.Rows.Count; i++)
- {
- // get the next DataRow in the DataTable
- DataRow dr = TheTable.Rows[i];
- int startxposition = TheDataGrid.Location.X;
- // Calculate the row boundary based on teh RowCount and offsets into the page
- RowBounds.X = TheDataGrid.Location.X; RowBounds.Y = TheDataGrid.Location.Y +
- TopMargin + ((RowCount - initialRowCount) + 1) * (TheDataGrid.Font.SizeInPoints +
- kVerticalCellLeeway);
- RowBounds.Height = TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway;
- RowBounds.Width = PageWidth;
- // save the vertical row positions for drawing grid lines
- Lines.Add(RowBounds.Bottom);
- // paint rows differently for alternate row colors
- if (i % 2 == 0)
- {
- g.FillRectangle(BackBrush, RowBounds);
- }
- else
- {
- g.FillRectangle(AlternatingBackBrush, RowBounds);
- }
- // Go through each column in the row and draw the information from the
- DataRowfor(int j = 0; j < TheTable.Columns.Count; j++)
- {
- RectangleF cellbounds = new RectangleF(startxposition,
- TheDataGrid.Location.Y + TopMargin + ((RowCount - initialRowCount) + 1) *
- (TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway),
- columnwidth,
- TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway);
- // draw the data at the next position in the row
- if (startxposition + columnwidth <= PageWidth)
- {
- g.DrawString(dr[j].ToString(), TheDataGrid.Font, ForeBrush, cellbounds, cellformat);
- lastRowBottom = (int)cellbounds.Bottom;
- }
- // increment the column position
- startxposition = startxposition + columnwidth;
- }
- RowCount++;
- // when we've reached the bottom of the page, draw the horizontal and vertical grid lines and return true
- if (RowCount * (TheDataGrid.Font.SizeInPoints + kVerticalCellLeeway) >
- PageHeight * PageNumber) - (BottomMargin + TopMargin))
- {
- DrawHorizontalLines(g, Lines); DrawVerticalGridLines(g, TheLinePen, columnwidth,
- lastRowBottom);
- return true;
- }
- }
- // when we've reached the end of the table, draw the horizontal and vertical gridlines and return false
- DrawHorizontalLines(g, Lines);
- DrawVerticalGridLines(g, TheLinePen, columnwidth, lastRowBottom);
- return false;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message.ToString());
- return false;
- }
Improvements
This class can be greatly improved by utilizing the DataGridColumnStyle class stored in the TableStyles property of the DataGrid. These properties allow you to specify different column width's for certain columns and different text alignments.

MarkRLVPosted Jul 10, 2022, 8:16 PM
Could you provide some information regarding how to turn the ZIP file into a project? I created a project DataGridPrinterMG and overlaid the zip file into the directory. Some things are not declared properly. Also would like to not have the source be the NorthWindDB but instead be a data table I create.
M MolinaPosted Mar 15, 2020, 7:13 PM
What if the DataGridView is populated by URL or a XML file load and the grid's DataSoure = none?
Ramesh PalaniappanPosted Sep 10, 2016, 9:40 AM
Good one
IsraelPosted Sep 17, 2015, 5:16 PM
Nice article Bro.
ChristinaPosted Feb 3, 2014, 6:05 AM
Thank you very much for sharing your knowledge. I have tried three non-working examples before I found this.
refaat hamedPosted Mar 22, 2013, 4:46 PM
thank you so much but , were is the data access Northwind.mdb????
niloufar azadPosted Aug 9, 2012, 2:10 AM
hello i am niloufar &from iran , i download project you and run but i create project and test from project ,in print printPreviewDialog,data datagridview dont send to preview? help from u? tanks.
SELASSI AbdellaheditedPosted Apr 5, 2011, 9:49 PMEdited Apr 5, 2011, 9:51 PM
I have a probleme, i need to print a data grid in x,y position i m founding this code but the print is always in x=0,y=0 :s . this is the code used : // Draw image to screen. ev.Graphics.DrawImage(newImage, ulCorner); ev.Graphics.DrawImage(newImage, ulCorner); ev.Graphics.DrawString(line, printFont, myBrush, leftMargin, yPosition + 170, new StringFormat()); PaintEventArgs myPaintArgs = new PaintEventArgs(ev.Graphics, new Rectangle(new Point(500, 300), this.Size)); this.InvokePaint(dataGrid, myPaintArgs); count++;
Bel MamPosted Feb 13, 2011, 10:07 AM
I want to thank you very much ,because I got headache before see this sample. king regard
elham rezaeiPosted Nov 1, 2010, 2:48 AM
hi Mike i want this program in C# 2008
NapsterPosted Sep 5, 2010, 6:56 AM
Good work Mike
syam seditedPosted Nov 23, 2009, 2:37 AMEdited Nov 23, 2009, 2:38 AM
It is quite helpfull.. i had been searching for this type of article for a long time.. Thanks a lot... Syam.S [email protected]
Tushar DalviPosted Sep 24, 2009, 12:25 AM
Hello Sir can u please give me the database file(NorthWind.mdb) of this code urgent
Greg DavisPosted Aug 25, 2009, 10:57 AM
Great Article! It is very helpful. I am working with DataGridView and I am able to get it to display, but my data needs to be displayed in Landscape form and my rows and columns need wraparound and I guess be wider. Can this be done?
Ana RojasPosted Mar 27, 2009, 5:00 AM
Hi Mike, Thank you for this great example. Just the one I needed, because I was trying to do the same thing and I couldn't do it rigth. Thank you for sharing your knowlegde with the rest of the people, who are learning too, like me. Thanks again, AnMatrix
cam tangPosted Feb 16, 2009, 5:03 AM
Thanks
Hasitha Indunil alexanderPosted Sep 24, 2008, 4:00 AM
Hi, I could overcome the my task using this. Hasitha
saeid asbousPosted Jan 26, 2008, 5:02 PM
I am iranian. my name is SAEID and thanks for programs. bye bye
tianyaeditedPosted Jan 14, 2008, 10:45 PMEdited Jan 14, 2008, 10:48 PM
when I use it,I have 140 datarows. last page is 70 but next page begins 73. 71and 72 lost.
karuna karanPosted Dec 20, 2007, 5:00 AM
i am developping one application software. i want to print the dataset tables report.
pedram shayaniPosted Sep 2, 2007, 5:09 AM
mr gold.i love u& your code.
jerome shijuPosted Jul 5, 2007, 1:17 AM
Hi Mike, I have a datagrid(printgrid) and button(print).please send the solution for when i click on the button to get the printout of datagrid items thanks jerome
SWLPosted Apr 23, 2007, 4:03 PM
Hi Mike, I read several of your articles regarding datagrid print. They are great! But I assume they are for WinForms. Do you have a version that allows printing the GridView in ASP.NET (web-based)? Thanks! SWL
sanjeev PeditedPosted Apr 18, 2007, 4:07 AMEdited Apr 18, 2007, 4:19 AM
Hi Mike, Thanks for such a great article, and I want to know about RenderControl here I am using this controls to print grid info... but after render its returning null value.... to calling function.... I am calling from Print function.... print.value=strPrint passing null value.... so please let me know how to work on this rendercontrols... i.e in print function..... private void btnPrint_ServerClick(object sender, System.EventArgs e) { string strPrint=GetHtml(theGrid) //then GetHtml function is calling strPrint=strPrint.Replace("\r",""); strPrint=strPrint.Replace("\t",""); strPrint=strPrint.Replace("\n",""); Print.Value =strPrint; // this document to get print isComplete.Value="1"; } string GetHtml(Control c) { StringWriter sw = new StringWriter(); HtmlTextWriter hw = new HtmlTextWriter(sw); c.RenderControl(hw); return sw.ToString(); } Thanks & Regards, Sanjay
SibiPosted Mar 16, 2007, 8:43 AM
Hello, great article Mike! but one problem i got: If i resize one cell and then print, it still shows the Datagrid without the resized cell/Row/Column. What iam doing wrong? Thanks! Sibi
jayshuklaPosted Mar 27, 2006, 1:24 PM
Hi Mike, I wanted to thank you for such a great sample. I was wondering if you have a version that allows printing the Data Grid View (VS.NET 2005), Appreicate if you could give any ideas or any alternatives that I could follow. Thanks JS