Click here to Skip to main content
15,884,099 members
Articles / Programming Languages / Visual Basic
Article

DataGridView Printing by Selecting Columns and Rows

Rate me:
Please Sign up or sign in to vote.
4.85/5 (102 votes)
11 Mar 2007CPOL3 min read 893.4K   45.9K   238   204
An article on DataGrdView printing.

Image 1

Image 2

Introduction

Sometimes the user needs to print specific columns and rows (or all of them) in a DataGridView. Some cases can be as below:

  • There are too many rows in a DataGridView and there is no need to print all of them.
  • Sum of the column widths may be wider than the page width, and it is better to remove one or more columns while printing.

So a class named PrintDGV was implemented, and can be used in any .NET2.0 application. I have done it both for the DataGrid and for the DataGridView, in C# and VB.NET.

Description

The main section of the code is the PrintDGV class and the PrintOptions form.

In the PrintDGV, we have:

  • The SelectedColumns and AvailableColumns lists to hold column names.
  • A PrintDocument object named PrintDoc (with the BeginPrint and PrintPage event handlers)
  • Four functions:
    • Print_DataGridView: 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.

The code has the following features :

  • Supports TextBox, Link, Button, ComboBox, CheckBox, and Image columns.
  • Draws the columns to fit on the page width, or draws them as they are shown.
  • Wraps the cell text if the cell width is smaller than its contents.
  • Draws the page footer, date, time, and the title on the page.

Using the code

For using the code in an application, the PrintDGV class and the PrintOptions form must be added to it, and then the function Print_DataGridView is called. In our example, the sample project has a Form named MainForm.

In the MainForm, the DataGridView is filled with 'Persons' table of the 'Persongs.mdb'.

In the PrintOption form, the DataGridView Columns, Fitting to page, and the Title can be selected by user.

The PrintDoc_PrintPage event handler does the following tasks :

  • Calculates the column widths.
  • Prints the current page, row by row - loops through all rows in the DataGridView.
  • In the 'Print Selected Rows' mode, if the current row is not selected, then skips it.
  • If it reaches the end of the page, then writes the page number and goes to the next page. If it doesn't reach the end of the page then:
  • If it is in a new page, then draws the title, date-time, headers, and columns (checks to see if each column was selected by the user, if not, skips it).
  • Draws the column contents for the TextBox, Link, Button, CheckBox, ComboBox, and Image cells (checks to see if each column was selected by the user, if not, skips it).
  • Draws the borders.
  • Calculates the 'Rows per Page' for the first page.
  • Writes the page footer (page number).
C#
private static void PrintDoc_PrintPage(object sender, 
        System.Drawing.Printing.PrintPageEventArgs e) 
{
    int tmpWidth, i;
    int tmpTop = e.MarginBounds.Top;
    int tmpLeft = e.MarginBounds.Left;
    int HeaderHeight=0;

    try 
    {            
        // Before starting first page, it saves
        // Width & Height of Headers and CoulmnType
        if (PageNo == 1) 
        {
            foreach (DataGridViewColumn GridCol in dgv.Columns)
            {
                if (!GridCol.Visible) continue;
                // Skip if the current column not selected
                if (!PrintDGV.SelectedColumns.Contains(
                     GridCol.HeaderText)) continue;

                // Detemining whether the columns
                // are fitted to the page or not.
                if (FitToPageWidth) 
                    tmpWidth = (int)(Math.Floor((double)(
                               (double)GridCol.Width / 
                               (double)TotalWidth * (double)TotalWidth * 
                               ((double)e.MarginBounds.Width / 
                                (double)TotalWidth))));
                else
                    tmpWidth = GridCol.Width;

                HeaderHeight = 
                   (int)(e.Graphics.MeasureString(GridCol.HeaderText,
                    GridCol.InheritedStyle.Font, tmpWidth).Height) + 11;

                // Save width & height of headres and ColumnType
                ColumnLefts.Add(tmpLeft);
                ColumnWidths.Add(tmpWidth);
                ColumnTypes.Add(GridCol.GetType());
                tmpLeft += tmpWidth;
            }
        }

        // Printing Current Page, Row by Row
        while (RowPos <= dgv.Rows.Count - 1)
        {
            DataGridViewRow GridRow = dgv.Rows[RowPos];
            if (GridRow.IsNewRow || (!PrintAllRows && !GridRow.Selected))
            {
                RowPos++;
                continue;
            }

            CellHeight = GridRow.Height;

            if (tmpTop + CellHeight >= 
                 e.MarginBounds.Height + e.MarginBounds.Top)
            {
                DrawFooter(e, RowsPerPage);
                NewPage = true;
                PageNo++;
                e.HasMorePages = true;
                return;
            }
            else
            {
                if (NewPage)
                {
                    // Draw Print Title
                    e.Graphics.DrawString(PrintTitle, 
                           new Font(dgv.Font, FontStyle.Bold), 
                            Brushes.Black, e.MarginBounds.Left, 
                            e.MarginBounds.Top -
                            e.Graphics.MeasureString(PrintTitle, 
                            new Font(dgv.Font, 
                            FontStyle.Bold), 
                            e.MarginBounds.Width).Height - 13);

                    String s = DateTime.Now.ToLongDateString() + " " + 
                               DateTime.Now.ToShortTimeString();
                    // Draw Time and Date    
                    e.Graphics.DrawString(s, 
                            new Font(dgv.Font, FontStyle.Bold), 
                            Brushes.Black, e.MarginBounds.Left + 
                            (e.MarginBounds.Width - 
                            e.Graphics.MeasureString(s, new Font(dgv.Font, 
                            FontStyle.Bold), e.MarginBounds.Width).Width), 
                            e.MarginBounds.Top - 
                            e.Graphics.MeasureString(PrintTitle, 
                            new Font(new Font(dgv.Font, 
                            FontStyle.Bold), FontStyle.Bold), 
                            e.MarginBounds.Width).Height - 13);

                    // Draw Headers
                    tmpTop = e.MarginBounds.Top;
                    i = 0;
                    foreach (DataGridViewColumn GridCol in dgv.Columns)
                    {
                        if (!GridCol.Visible) continue;
                        if (!PrintDGV.SelectedColumns.Contains(
                                            GridCol.HeaderText)) 
                            continue;

                        e.Graphics.FillRectangle(new 
                            SolidBrush(Color.LightGray), 
                            new Rectangle((int) ColumnLefts[i], tmpTop,
                            (int)ColumnWidths[i], HeaderHeight));

                        e.Graphics.DrawRectangle(Pens.Black, 
                            new Rectangle((int) ColumnLefts[i], tmpTop,
                            (int)ColumnWidths[i], HeaderHeight));

                        e.Graphics.DrawString(GridCol.HeaderText, 
                            GridCol.InheritedStyle.Font, 
                            new SolidBrush(GridCol.InheritedStyle.ForeColor),
                            new RectangleF((int)ColumnLefts[i], tmpTop, 
                            (int)ColumnWidths[i], HeaderHeight), StrFormat);
                        i++;
                    }
                    NewPage = false;
                    tmpTop += HeaderHeight;
                }

                // Draw Columns Contents
                i = 0;
                foreach (DataGridViewCell Cel in GridRow.Cells)
                {
                    if (!Cel.OwningColumn.Visible) continue;
                    if (!SelectedColumns.Contains(
                            Cel.OwningColumn.HeaderText))
                        continue;

                    // For the TextBox Column
                    if (((Type) ColumnTypes[i]).Name == 
                         "DataGridViewTextBoxColumn" || 
                        ((Type) ColumnTypes[i]).Name == 
                         "DataGridViewLinkColumn")
                    {
                        e.Graphics.DrawString(Cel.Value.ToString(), 
                                Cel.InheritedStyle.Font, 
                                new SolidBrush(Cel.InheritedStyle.ForeColor),
                                new RectangleF((int)ColumnLefts[i], 
                                (float)tmpTop,
                                (int)ColumnWidths[i], 
                                (float)CellHeight), StrFormat);
                    }
                    // For the Button Column
                    else if (((Type) ColumnTypes[i]).Name == 
                                     "DataGridViewButtonColumn")
                    {
                        CellButton.Text = Cel.Value.ToString();
                        CellButton.Size = new Size((int)ColumnWidths[i], 
                                                    CellHeight);
                        Bitmap bmp = new Bitmap(CellButton.Width, 
                                                CellButton.Height);
                        CellButton.DrawToBitmap(bmp, new Rectangle(0, 0, 
                                bmp.Width, bmp.Height));
                        e.Graphics.DrawImage(bmp, 
                          new Point((int)ColumnLefts[i], tmpTop));
                    }
                    // For the CheckBox Column
                    else if (((Type) ColumnTypes[i]).Name == 
                              "DataGridViewCheckBoxColumn")
                    {
                        CellCheckBox.Size = new Size(14, 14);
                        CellCheckBox.Checked = (bool)Cel.Value;
                        Bitmap bmp = new Bitmap((int)ColumnWidths[i], 
                                                 CellHeight);
                        Graphics tmpGraphics = Graphics.FromImage(bmp);
                        tmpGraphics.FillRectangle(Brushes.White, 
                                new Rectangle(0, 0, 
                                bmp.Width, bmp.Height));
                        CellCheckBox.DrawToBitmap(bmp, 
                                new Rectangle((int)((bmp.Width - 
                                CellCheckBox.Width) / 2), 
                                (int)((bmp.Height - CellCheckBox.Height) / 2), 
                                CellCheckBox.Width, CellCheckBox.Height));
                        e.Graphics.DrawImage(bmp, 
                                new Point((int)ColumnLefts[i], tmpTop));
                    }
                    // For the ComboBox Column
                    else if (((Type) ColumnTypes[i]).Name == 
                              "DataGridViewComboBoxColumn")
                    {
                        CellComboBox.Size = new Size((int)ColumnWidths[i], 
                                                CellHeight);
                        Bitmap bmp = new Bitmap(CellComboBox.Width, 
                                                CellComboBox.Height);
                        CellComboBox.DrawToBitmap(bmp, new Rectangle(0, 0, 
                                bmp.Width, bmp.Height));
                        e.Graphics.DrawImage(bmp, 
                                new Point((int)ColumnLefts[i], tmpTop));
                        e.Graphics.DrawString(Cel.Value.ToString(), 
                                Cel.InheritedStyle.Font, 
                                new SolidBrush(Cel.InheritedStyle.ForeColor), 
                                new RectangleF((int)ColumnLefts[i] + 1, 
                                tmpTop, (int)ColumnWidths[i]
                                - 16, CellHeight), StrFormatComboBox);
                    }
                    // For the Image Column
                    else if (((Type) ColumnTypes[i]).Name == 
                              "DataGridViewImageColumn")
                    {
                        Rectangle CelSize = new Rectangle((int)ColumnLefts[i], 
                                tmpTop, (int)ColumnWidths[i], CellHeight);
                        Size ImgSize = ((Image)(Cel.FormattedValue)).Size;
                        e.Graphics.DrawImage((Image)Cel.FormattedValue, 
                                new Rectangle((int)ColumnLefts[i] + 
                                (int)((CelSize.Width - ImgSize.Width) / 2), 
                                tmpTop + (int)((CelSize.Height - 
                                ImgSize.Height) / 2), 
                                ((Image)(Cel.FormattedValue)).Width, 
                                ((Image)(Cel.FormattedValue)).Height));

                    }

                    // Drawing Cells Borders 
                    e.Graphics.DrawRectangle(Pens.Black, 
                            new Rectangle((int)ColumnLefts[i], 
                            tmpTop, (int)ColumnWidths[i], CellHeight));

                    i++;

                }
                tmpTop += CellHeight;
            }

            RowPos++;
            // For the first page it calculates Rows per Page
            if (PageNo == 1) RowsPerPage++;
        }

        if (RowsPerPage == 0) return;

        // Write Footer (Page Number)
        DrawFooter(e, RowsPerPage);

        e.HasMorePages = false;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", 
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Error);
    }
}

History

Two bugs fixed (22 Feb 2007):

  • The number of pages in the C# code was wrong.
  • For the pages after the first page, the column headers were overwriting the first row ( both in the C# code and the VB code).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGood job Pin
kule16-Oct-08 7:42
kule16-Oct-08 7:42 
Questionright to left header Pin
masoom.eslami3-Sep-08 17:57
masoom.eslami3-Sep-08 17:57 
QuestionQuestion Pin
Member 51231549-Jul-08 0:52
Member 51231549-Jul-08 0:52 
GeneralExcellent Code ,But how to change page size- to Legal,or Letter Pin
NOUFIi20-Jun-08 2:43
NOUFIi20-Jun-08 2:43 
GeneralRe: Excellent Code ,But how to change page size- to Legal,or Letter Pin
Afrasiab Cheraghi21-Jun-08 8:07
Afrasiab Cheraghi21-Jun-08 8:07 
GeneralRe: Excellent Code ,But how to change page size- to Legal,or Letter Pin
Member 400641128-Dec-09 21:45
Member 400641128-Dec-09 21:45 
QuestionAlignment doesn't work for me, Please Help Pin
Nguyễn Ái Triết14-Jun-08 22:56
Nguyễn Ái Triết14-Jun-08 22:56 
QuestionWhy all static methods? Pin
daylightdj28-May-08 4:11
daylightdj28-May-08 4:11 
Great code, but I have a question about the design.

Why did you choose to make all of your methods static?
Why did you choose to create a static class instead of normal class?

Was this jus the easy way out, or was there some thought / design process that brought you to this conclusion?
Either way, please let me know.

Is there some threading reason that you chose static?
Do you know why you would choose static over normal?

Thanks,

radink
AnswerRe: Why all static methods? Pin
Afrasiab Cheraghi29-May-08 16:03
Afrasiab Cheraghi29-May-08 16:03 
QuestionQuestion Pin
Member 51231543-May-08 19:57
Member 51231543-May-08 19:57 
AnswerRe: Question Pin
Afrasiab Cheraghi6-May-08 7:48
Afrasiab Cheraghi6-May-08 7:48 
GeneralRe: Question Pin
Member 51231547-May-08 1:29
Member 51231547-May-08 1:29 
Generalcolumn width Pin
mohabati30-Apr-08 7:27
mohabati30-Apr-08 7:27 
GeneralRe: column width Pin
Afrasiab Cheraghi30-Apr-08 13:45
Afrasiab Cheraghi30-Apr-08 13:45 
Questionplease help me [modified] Pin
Member 512315428-Apr-08 20:53
Member 512315428-Apr-08 20:53 
AnswerRe: please help me Pin
Afrasiab Cheraghi29-Apr-08 17:56
Afrasiab Cheraghi29-Apr-08 17:56 
Generalthanks Pin
Member 51231542-May-08 18:17
Member 51231542-May-08 18:17 
GeneralRow Height Problem [modified] Pin
Kathir_Itguy27-Apr-08 9:45
Kathir_Itguy27-Apr-08 9:45 
AnswerRe: Row Height Problem Pin
Afrasiab Cheraghi29-Apr-08 17:34
Afrasiab Cheraghi29-Apr-08 17:34 
QuestionRe: Row Height Problem Pin
Jeremy197629-Nov-08 15:09
Jeremy197629-Nov-08 15:09 
GeneralThanks for your reply me Pin
kindly naghme24-Apr-08 23:23
kindly naghme24-Apr-08 23:23 
GeneralRe: Thanks for your reply me Pin
Afrasiab Cheraghi25-Apr-08 7:34
Afrasiab Cheraghi25-Apr-08 7:34 
Generalvery Excelent Code Pin
kindly naghme23-Apr-08 22:54
kindly naghme23-Apr-08 22:54 
AnswerRe: very Excelent Code Pin
Afrasiab Cheraghi24-Apr-08 13:18
Afrasiab Cheraghi24-Apr-08 13:18 
Questionproblem : right to left language PinPopular
mohabati13-Apr-08 8:41
mohabati13-Apr-08 8:41 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.