Click here to Skip to main content
Click here to Skip to main content

Printing Selected Columns and Rows in a DataGrid

By , 13 Dec 2006
 

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.
// Print Current Page, Row by Row 
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)
        {
            // Draw Header
            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);

            // Draw Columns
            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;
        // Draw Columns Contents
        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")
            {
                // For the TextBox Column
                // Draw Content of TextBox Cell
                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")
            {
                // For the CheckBox Column
                // Draw Content of CheckBox Cell
                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++;
    // For the first page it calculates Rows per Page
    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.)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Afrasiab Cheraghi
Web Developer
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionthankmemberwxszx13 Jul '12 - 16:26 
thanks!!!
Questionquestionmemberlami200624 Jan '12 - 5:30 
salut
merci pour votre article , elle est vraiment trés utile et trés interssante
la question est : pourquoi les dates s'affichent 12/12/2005 00.00.0000 je veux afficher juste la forme courte de la date
GeneralMy vote of 5memberkmlslm6 Sep '10 - 15:08 
Hi, Mr Cheraghi!
Good practical program, although I've not check your codes clarity yet!
a lot Thanks!
kmlslm
GeneralGreat codememberAngel Kafazov19 Dec '08 - 3:40 
Thanks a lot for the contribution, very useful indeed!
GenerallandscapememberPedro_FP_Simoes15 Oct '08 - 1:53 
Hi, your code is amazing, it gives me the capability to build a lot of very simple tabular printable reports in a short time, without Crystal reports or RDLC's, thanks. Wink | ;)
 
I had the necessity to print in landscape mode and without the printoptions form, so I added this pieces of code in the printdoc_printpage:
 
to landscape it:
If printDoc.DefaultPageSettings.Landscape Then
    With printDoc.DefaultPageSettings
        Dim old As Printing.PaperSize = .PaperSize
        .PaperSize = New Printing.PaperSize(old.PaperName & " landscape", old.Height, old.Width)
    End With
End If
 
to print directly:
 Public Shared Sub Print_DataGrid(ByVal dg1 As DataGrid, ByVal PrintTitle As String, ByVal PrinterName As String)
	Dim ppvw As PrintPreviewDialog
	Try
		' Save DataGrid attributes
		dg = dg1
		PrintFont = dg.Font
		PrintFontColor = dg.ForeColor
 
		' Get all Coulmns Names in the DataGrid
		AvailableColumns.Clear()
		For Each c As DataGridColumnStyle In dg.TableStyles(0).GridColumnStyles
			AvailableColumns.Add(c.HeaderText)
		Next
 
		' Show PrintOption Form
		'Dim dlg As New PrintOptions(PrintTitle, AvailableColumns)
		'If dlg.ShowDialog() <> DialogResult.OK Then Exit Sub

		PrintDG.PrintTitle = PrintTitle
		PrintDG.PrintAllRows = True
		PrintDG.SelectedColumns = AvailableColumns
 
		'If dlg.PrintFont IsNot Nothing Then PrintFont = dlg.PrintFont
		'If dlg.PrintFontColor.Name <> "" And dlg.PrintFontColor.Name <> "0" Then
		'    PrintFontColor = dlg.PrintFontColor
		'End If

		printDoc.PrinterSettings.PrinterName = PrinterName
		printDoc.DefaultPageSettings.Landscape = True
 
		RowsPerPage = 0
 
		ppvw = New PrintPreviewDialog
		ppvw.Document = printDoc
 
		' Show Print Preview Page
		If ppvw.ShowDialog() <> DialogResult.OK Then Exit Sub
 
		' Print the Documnet
		printDoc.Print()
 
	Catch ex As Exception
		MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
	Finally
 
	End Try
End Sub
 
I have to insert an flag in the print function paramenters to control the landscape mode.
 
Thank you for this great piece of code Big Grin | :-D
GeneralPrintDataGrid_src_cs.zip not file can be downloadedmembere_matrix11 Aug '08 - 8:06 
help
I need the source code Download source [C #] - 68.1 Kb
 
PrintDataGrid_src_cs.zip
I can not download the code anything go wrong
 
brother if you can spend full code please
VB.NEt try to translate to C # and gives many errors
Mr. AFRASIAB Cheraghi
may send my mail
opennetsys@hotmail.com
Thank you
GeneralBug maybemembernewToThisThingy17 Apr '07 - 22:48 
In PrintDG ShowFooter method:
 
string sPageNo = PageNo.ToString() + " of " +
Math.Ceiling((double)(cnt / RowsPerPage)).ToString();
 
should be:
 
string sPageNo = PageNo.ToString() + " of " +
Math.Ceiling((double)((float)cnt / (float)RowsPerPage)).ToString();
 
I've done some dirty change to code so it can print DataGridView, if you are interested i'll mail it.
GeneralRe: Bug maybememberAfrasiab Cheraghi18 Apr '07 - 7:25 
About the ShowFooter method you are right.
 
I did the code for the DataGridView, you can go to :
 
http://www.codeproject.com/csharp/PrintDataGridView.asp

GeneralRe: Bug maybemembernewToThisThingy19 Apr '07 - 3:33 
Well didn't find that. Would save me a hour or so, no matter, thanks.
QuestionError when print all records?memberkhanhdl30 Nov '06 - 16:10 
Hi,
I tried your code, and everything works fine but:
 
When print all records with <Option Print>\\Selected-->error:Attempted to divide by zero!
I don't understand!
 
Thanks

AnswerRe: Error when print all records?memberAfrasiab Cheraghi30 Nov '06 - 18:28 
Hi khanhdl,
 
You are right. when there is no selected row in the DataGrid, using of the Print Option 'Selected rows' is meaningless. So in this case either the 'Selected' RadioButton must be disabled or print nothing.
For printing all rows we can either use the 'All rows' option or selecting all rows(Ctrl+A) and then use 'Selected' option.
 
This is a bug and i will fix it soon.
 
To Fix:
In the PrintDG class --> printDoc_PrintPage event handler we add following line :
 
if (RowsPerPage == 0) return;
 
before this :
 
// Write Footer (Page Number)
DrawFooter(e, RowsPerPage);
e.HasMorePages = false;
 

Indeed in this case there is no rows for print but it tries to write footer so rise an Error.
 

Thanks
Afra
GeneralRe: Error when print all records?memberkhanhdl30 Nov '06 - 21:04 
Thanks for answer my question.
I tried add code:
In the PrintDG class -->Print_DataGrid:
 
// Show PrintOption Form
...
if(!dlg.PrintAllRows && !dg.IsSelected(0))
PrintAllRows = true;
else
PrintAllRows = dlg.PrintAllRows;
 
No problem happened!
Have good health!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 13 Dec 2006
Article Copyright 2006 by Afrasiab Cheraghi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid