Introduction
Existing articles about DataGrid
printing can only print all columns and rows. Sometimes a user needs to print specific columns and rows in a DataGrid
. Some cases can be as below:
- There are a very high number of rows in a
DataGrid
and there is no need to print all of them.
- Sum of the column widths may be longer than the page width and it is better to remove one or more columns while printing.
- The user wants to filter the
DataGrid
contents and then print the filtered data.
So a class named PrintDG
was implemented, and it can be used in an application. I have done it both for DataGrid
and DataGridView
, in C# and VB.NET.
Description
The main section of the code is the PrintDG
class.
In the PrintDG
, we have:
- The
SelectedColumns
and AvailableColumns
lists to hold column names.
- A
PrintDocument
object named PrintDoc
(with BeginPrint
and PrintPage
events handlers).
- Four functions:
Print_DataGrid
: The main function that can be called from outside of the class.
PrintDoc_BeginPrint
: Initializes some variables to begin printing.
PrintDoc_PrintPage
: Performs the printing job.
DrawFooter
: Writes the page number.
Using the code
For using the PrintDG
class, the DataGrid
must have a TableSyle
, dg.TableStyles[0]
. In the Main Form, the DataGrid
is filled with the 'Order' table of 'Northwind.mdb', and a TableStyle
for the DataGrid
is defined. In the PrintOption Form, the DataGrid
columns, font, fore-color, and title can be selected by the user.
Here is a section of code in the PrintDoc_PrintPage
event handler. It does the following tasks:
- Loops through all rows in the
DataView
.
- In the 'Print Selected Rows' mode, if current row not selected, then ignore it.
- If it reaches the end of the page, then write page number and go to the next page. If it doesn't reach the end of page then:
- If it is in a new page, then draw headers and columns (it checks to see if each column was selected by the user, if not, will skip it).
- Draw the column contents for the
TextBoxColumn
and BoolColumn
(it checks to see if each column was selected by the user, if not, will skip it)
- Draw the borders.
- Calculate 'Rows per Page' for the first page.
while (RowPos <= dv.Count - 1)
{
if (!PrintAllRows && !dg.IsSelected(RowPos))
{
RowPos++;
continue;
}
DataRowView oRow = dv[RowPos];
if (nTop + nHeight >= e.MarginBounds.Height + e.MarginBounds.Top)
{
DrawFooter(e, RowsPerPage);
NewPage = true;
PageNo++;
e.HasMorePages = true;
return;
}
else
{
if (NewPage)
{
e.Graphics.DrawString(PrintTitle,
new Font(PrintFont, FontStyle.Bold),
Brushes.Black, e.MarginBounds.Left,
e.MarginBounds.Top -
e.Graphics.MeasureString(PrintTitle,
new Font(PrintFont, FontStyle.Bold),
e.MarginBounds.Width).Height - 13);
string s = DateTime.Now.ToLongDateString() + " " +
DateTime.Now.ToShortTimeString();
e.Graphics.DrawString(s, new Font(PrintFont,
FontStyle.Bold), Brushes.Black,
e.MarginBounds.Left + (e.MarginBounds.Width -
e.Graphics.MeasureString(s,
new Font(PrintFont, FontStyle.Bold),
e.MarginBounds.Width).Width), e.MarginBounds.Top -
e.Graphics.MeasureString(PrintTitle,
new Font(new Font(PrintFont, FontStyle.Bold),
FontStyle.Bold),
e.MarginBounds.Width).Height - 13);
nTop = e.MarginBounds.Top;
i = 0;
foreach (DataGridColumnStyle GridCol in
dg.TableStyles[0].GridColumnStyles)
{
if (!PrintDG.SelectedColumns.Contains(GridCol.HeaderText))
continue;
e.Graphics.FillRectangle(new SolidBrush(Color.LightGray),
new Rectangle((int) ColumnLefts[i],
nTop, (int) ColumnWidths[i], nHeight));
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int) ColumnLefts[i], nTop,
(int) ColumnWidths[i], nHeight));
e.Graphics.DrawString(GridCol.HeaderText, PrintFont,
new SolidBrush(PrintFontColor),
new RectangleF((int) ColumnLefts[i],nTop,
(int) ColumnWidths[i], nHeight), StrFormat);
i++;
}
NewPage = false;
}
nTop += nHeight;
i = 0;
foreach (DataGridColumnStyle oColumn in
dg.TableStyles[0].GridColumnStyles)
{
if (!PrintDG.SelectedColumns.Contains(oColumn.HeaderText))
continue;
string cellval = oRow.Row[oColumn.MappingName].ToString().Trim();
if (ColumnTypes[i].ToString() ==
"System.Windows.Forms.DataGridTextBoxColumn")
{
e.Graphics.DrawString(cellval, PrintFont,
new SolidBrush(PrintFontColor),
new RectangleF((int) ColumnLefts[i], nTop,
(int) ColumnWidths[i], nHeight), StrFormat);
}
else if (ColumnTypes[i].ToString() ==
"System.Windows.Forms.DataGridBoolColumn")
{
ChkBox.Size = new Size(14, 14);
ChkBox.Checked = (bool) (oRow.Row[oColumn.MappingName]);
Bitmap oBitmap = new Bitmap((int) ColumnWidths[i], nHeight);
Graphics oTempGraphics = Graphics.FromImage(oBitmap);
oTempGraphics.FillRectangle(Brushes.White,
new Rectangle(0, 0, oBitmap.Width, oBitmap.Height));
ChkBox.DrawToBitmap(oBitmap,
new Rectangle((int)((oBitmap.Width - ChkBox.Width) / 2),
(int) ((oBitmap.Height - ChkBox.Height) / 2),
ChkBox.Width, ChkBox.Height));
e.Graphics.DrawImage(oBitmap,
new Point((int) ColumnLefts[i], nTop));
}
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int) ColumnLefts[i],
nTop, (int) ColumnWidths[i], nHeight));
i++;
}
}
RowPos++;
if (PageNo == 1) RowsPerPage++;
}
History
- December 12, 2006: Bug fixed - When there is no selected row, then trying to set 'Rows to print' = 'Selected rows' might cause 'Division by zero' error message. (Thanks to khanhdl.)