Click here to Skip to main content
11,477,007 members (75,187 online)
Click here to Skip to main content

A class to print and print preview a DataGrid control

, 6 Apr 2006 CPOL 299.2K 5.3K 116
Rate this:
Please Sign up or sign in to vote.
A class to add to your application to generate nicely formatted prints from a DataGrid.

Introduction

The System.Windows.Forms.DataGrid control is one of the most powerful and frequently used controls in the .NET arsenal and this class (DataGridPrinter) adds functionality to allow you to generate print and print previews from your data grid in a tidy and customizable layout.

To draw a grid, first draw a square

The basic operation when drawing a data grid is to draw a rectangle and fit text inside it. To do this I have a single subroutine called DrawCellString which draws a string inside a cell according to the alignment and format parameters passed in.

Public Function DrawCellString(ByVal s As String, _
      ByVal HorizontalAlignment As CellTextHorizontalAlignment, _
      ByVal VerticalAlignment As CellTextVerticalAlignment, _
      ByVal BoundingRect As Rectangle, _
      ByVal DrawRectangle As Boolean, _
      ByVal Target As Graphics, _
      ByVal PrintFont As Font)


        Dim x As Single, y As Single

        If DrawRectangle Then
            Target.DrawRectangle(_GridPen, BoundingRect)
        End If

        '\\ Set the text alignment
        If HorizontalAlignment = 
              CellTextHorizontalAlignment.LeftAlign Then
            _Textlayout.Alignment = StringAlignment.Near
        ElseIf HorizontalAlignment = 
                   CellTextHorizontalAlignment.RightAlign _
        Then
             _Textlayout.Alignment = StringAlignment.Far
        Else
             _Textlayout.Alignment = StringAlignment.Center
        End If

        Dim BoundingRectF As New RectangleF(BoundingRect.X + _CellGutter, _ 
                                BoundingRect.Y + _CellGutter,  _ 
                                BoundingRect.Width - (2 * _CellGutter),  _ 
                                BoundingRect.Height - (2 * _CellGutter))

        Target.DrawString(s, PrintFont, System.Drawing.Brushes.Black, _ 
                          BoundingRectF, _Textlayout)

End Function

There are two class level variables that are used to define how a cell is drawn: CellGutter specifies a margin (in pixels) between the edge of the string bounding box and the GridPen is the pen used to draw the box.

Now you can draw a box, you can draw a row

There are two types of rows you need to print in order to print a grid: a row of column headers and a row of data. This class always starts each new page with a row of column headers.

    Private Sub PrintGridHeaderLine(ByVal e As _
              System.Drawing.Printing.PrintPageEventArgs)

        Dim Top As Double = _PageContentRectangle.Top
        Dim Bottom As Double = Top + _Rowheight + (2 * _CellGutter)

        Top = RoundTo(Top, 2)
        Bottom = RoundTo(Bottom, 2)

        Dim nColumn As Integer

        For nColumn = 0 To GridColumnCount() - 1
            Dim rcCell As New Rectangle(_ColumnBounds(nColumn).Left, Top, _
                                 _ColumnBounds(nColumn).Width, Bottom - Top)
            Call DrawCellString(GetColumnHeadingText(nColumn),  _ 
                                CellTextHorizontalAlignment.CentreAlign, _
                                CellTextVerticalAlignment.MiddleAlign, _ 
                                rcCell, True, e.Graphics, _PrintFont)
        Next
    End Sub

This is fairly straightforward. The only tricky bit is getting the title of the column from the data grid which is done thus:

    Private Function GetColumnHeadingText(ByVal Column As Integer) As String

        If TypeOf _DataGrid.DataSource Is DataTable Then
            Return CType(_DataGrid.DataSource, _
                        DataTable).Columns(Column).ToString
        ElseIf TypeOf _DataGrid.DataSource Is DataSet Then
            Return CType(_DataGrid.DataSource, DataSet).Tables( _
                      _DataGrid.DataMember).Columns(Column).ToString
        ElseIf TypeOf _DataGrid.DataSource Is DataView Then
            Return CType(_DataGrid.DataSource, _
                    DataView).Table.Columns(Column).ToString
        Else
            'TODO : Get the column caption....
        End If
    End Function

And to print a row of data we do the same thing but with the row content of the current row:

Private Sub PrintGridLine(ByVal e As _
         System.Drawing.Printing.PrintPageEventArgs, _ 
              ByVal RowNumber As Integer)

        Dim RowFromTop As Integer = RowNumber + 1 - _CurrentPrintGridLine
        Dim Top As Double = _PageContentRectangle.Top + (RowFromTop * _
                                         ((_CellGutter * 2) + _Rowheight))
        Dim Bottom As Double = Top + _Rowheight + (2 * _CellGutter)

        Top = RoundTo(Top, 2)
        Bottom = RoundTo(Bottom, 2)

        Dim Items() As Object

            If TypeOf _DataGrid.DataSource Is DataTable Then
                Items = CType(_DataGrid.DataSource, _
                        System.Data.DataTable).DefaultView.Item(_
                                         RowNumber - 1).Row.ItemArray
            ElseIf TypeOf _DataGrid.DataSource Is DataSet Then
                Items = CType(_DataGrid.DataSource, _
                              System.Data.DataSet).Tables(     _
                                _DataGrid.DataMember).DefaultView.Item(_
                                             RowNumber - 1).Row.ItemArray
            ElseIf TypeOf _DataGrid.DataSource Is DataView Then
                Items = CType(_DataGrid.DataSource, _
                         System.Data.DataView).Table.DefaultView.Item( _
                                             RowNumber - 1).Row.ItemArray
            Else
                'TODO : Get the content for the current row from the data 
                '       source ....
            End If

            Dim nColumn As Integer
            For nColumn = 0 To Items.Length - 1
                Dim rcCell As New Rectangle(_ColumnBounds(nColumn).Left, Top,_
                       _ColumnBounds(nColumn).Width, Bottom - Top)
                Call DrawCellString(Items(nColumn).ToString, _ 
                               CellTextHorizontalAlignment.CentreAlign, _ 
                               CellTextVerticalAlignment.MiddleAlign,  _ 
                               rcCell, True, e.Graphics, _PrintFont)
            Next
End Sub

Fitting it all onto a page

The printed page is divided into three areas: the header, the body and the footer. There is also an InterSectionSpacing property that specifies a gap to use between the sections. These are all expressed as percentages of the page height and setting any of them to zero will omit that section.

The body section is worked out from what remains of the page height when the header, footer and inter section spacing have been added up and this is used to calculate how many rows can possibly fit on each page:

    Private Function RowsPerPage(ByVal GridLineFont As Font, _
                                ByVal e As Graphics) As Integer

        Return (_PageContentRectangle.Height / _ 
                ((_CellGutter * 2) + _Rowheight)) - 2

    End Function

Settings that change the look of the grid

The color and width of the lines around the sections can be set with the HeaderPen, FooterPen and GridPen properties respectively.

The font to use for each of the sections can be set with the HeaderFont, FooterFont and PrintFont properties respectively.

Using the class to preview and print a DataGrid

If you have a data grid on a form that you want to preview and optionally print using this class you can add a System.Windows.Forms.PrintPreviewDialog to your form and a Print menu and add the following code to it:

    Private GridPrinter As DataGridPrinter

    Private Sub MenuItem_File_print_Click(ByVal sender As Object, _ 
                                   ByVal e As System.EventArgs) _ 
                                   Handles MenuItem_File_print.Click

        If GridPrinter Is Nothing Then
            GridPrinter = New DataGridPrinter(Me.DataGrid1)
        End If

        With GridPrinter
            .HeaderText = "Some text"
            .HeaderHeightPercent = 10
            .FooterHeightPercent = 5
            .InterSectionSpacingPercent = 2
            '\\ Set any other properties to 
            'affect the look of the grid...
        End With

        With Me.PrintPreviewDialog1
            .Document = GridPrinter.PrintDocument
            If .ShowDialog = DialogResult.OK Then
                GridPrinter.Print()
            End If
        End With
    End Sub

License

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

Share

About the Author

Duncan Edwards Jones
Software Developer (Senior)
Ireland Ireland
C# / SQL Server developer
Microsoft MVP 2006, 2007
Visual Basic .NET
Follow on   Twitter   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 Pin
manoj kumar choubey19-Feb-12 20:55
membermanoj kumar choubey19-Feb-12 20:55 
QuestionHeader and logo image Pin
lucausa7523-Jun-11 0:23
memberlucausa7523-Jun-11 0:23 
GeneralUnable to preview or print multiple pages Pin
Olympia Sports18-Oct-10 10:29
memberOlympia Sports18-Oct-10 10:29 
GeneralRe: Unable to preview or print multiple pages Pin
Duncan Edwards Jones20-Oct-10 13:46
memberDuncan Edwards Jones20-Oct-10 13:46 
Generalproblem with drawing the color Pin
darkyro4-Aug-10 4:49
memberdarkyro4-Aug-10 4:49 
GeneralRe: problem with drawing the color Pin
Duncan Edwards Jones4-Aug-10 6:05
memberDuncan Edwards Jones4-Aug-10 6:05 
QuestionIs there a version to print a DataGridView control? Pin
andrewolff1-Aug-10 3:53
memberandrewolff1-Aug-10 3:53 
AnswerRe: Is there a version to print a DataGridView control? Pin
Member 220867920-Jan-11 1:18
memberMember 220867920-Jan-11 1:18 
QuestionDo you have a version to print the contents of a ListView control? Pin
andrewolff31-Jul-10 22:23
memberandrewolff31-Jul-10 22:23 
AnswerRe: Do you have a version to print the contents of a ListView control? Pin
Duncan Edwards Jones1-Aug-10 0:07
memberDuncan Edwards Jones1-Aug-10 0:07 
GeneralRe: Do you have a version to print the contents of a ListView control? Pin
andrewolff1-Aug-10 3:55
memberandrewolff1-Aug-10 3:55 
GeneralCool! And looks useful as well. Pin
Shane Story18-May-10 5:57
memberShane Story18-May-10 5:57 
GeneralPrintout format is different from the DataGridView format. Pin
Matthew Graham125-Feb-10 7:27
memberMatthew Graham125-Feb-10 7:27 
GeneralRe: Printout format is different from the DataGridView format. Pin
Duncan Edwards Jones25-Feb-10 11:11
memberDuncan Edwards Jones25-Feb-10 11:11 
GeneralRe: Printout format is different from the DataGridView format. Pin
Matthew Graham125-Feb-10 11:29
memberMatthew Graham125-Feb-10 11:29 
QuestionPrint Preview doesn't show datagridview Pin
mcf.white18-Mar-09 8:06
membermcf.white18-Mar-09 8:06 
AnswerRe: Print Preview doesn't show datagridview Pin
Duncan Edwards Jones18-Mar-09 12:07
memberDuncan Edwards Jones18-Mar-09 12:07 
GeneralRe: Print Preview doesn't show datagridview Pin
mcf.white23-Mar-09 3:01
membermcf.white23-Mar-09 3:01 
GeneralRe: Print Preview doesn't show datagridview Pin
Duncan Edwards Jones23-Mar-09 9:49
memberDuncan Edwards Jones23-Mar-09 9:49 
QuestionGreat Work! Pages Across vs Columns Per Page? Pin
David Gindler9-Dec-08 17:21
memberDavid Gindler9-Dec-08 17:21 
AnswerRe: Great Work! Pages Across vs Columns Per Page? Pin
Duncan Edwards Jones9-Dec-08 21:48
memberDuncan Edwards Jones9-Dec-08 21:48 
GeneralRe: Great Work! Pages Across vs Columns Per Page? Pin
David Gindler10-Dec-08 11:51
memberDavid Gindler10-Dec-08 11:51 
GeneralEmpty page Pin
Penko Mitev21-Sep-08 11:07
memberPenko Mitev21-Sep-08 11:07 
GeneralRe: Empty page Pin
Duncan Edwards Jones21-Sep-08 11:30
memberDuncan Edwards Jones21-Sep-08 11:30 
GeneralRe: Empty page Pin
Penko Mitev22-Sep-08 0:20
memberPenko Mitev22-Sep-08 0:20 
GeneralRe: Empty page Pin
Duncan Edwards Jones22-Sep-08 1:49
memberDuncan Edwards Jones22-Sep-08 1:49 
GeneralRe: Empty page Pin
Penko Mitev22-Sep-08 4:05
memberPenko Mitev22-Sep-08 4:05 
GeneralRe: Empty page Pin
Penko Mitev22-Sep-08 7:47
memberPenko Mitev22-Sep-08 7:47 
GeneralRe: Empty page Pin
Duncan Edwards Jones30-Sep-08 1:35
memberDuncan Edwards Jones30-Sep-08 1:35 
GeneralRe: Empty page Pin
Penko Mitev30-Sep-08 1:36
memberPenko Mitev30-Sep-08 1:36 
GeneralThanx Pin
jalpam15-Sep-08 21:16
memberjalpam15-Sep-08 21:16 
GeneralRe: Thanx Pin
Duncan Edwards Jones15-Sep-08 21:52
memberDuncan Edwards Jones15-Sep-08 21:52 
GeneralHi Pin
T. Ravindran31-Aug-08 22:37
memberT. Ravindran31-Aug-08 22:37 
GeneralRe: Hi Pin
Duncan Edwards Jones2-Sep-08 11:09
memberDuncan Edwards Jones2-Sep-08 11:09 
QuestionChoose which columns to print? Pin
Tim Hall25-Mar-08 8:51
memberTim Hall25-Mar-08 8:51 
AnswerRe: Choose which columns to print? Pin
Duncan Edwards Jones25-Mar-08 19:34
memberDuncan Edwards Jones25-Mar-08 19:34 
GeneralRe: Choose which columns to print? Pin
Tim Hall27-Mar-08 9:19
memberTim Hall27-Mar-08 9:19 
GeneralRe: Choose which columns to print? Pin
Duncan Edwards Jones27-Mar-08 17:17
memberDuncan Edwards Jones27-Mar-08 17:17 
QuestionProblem with receiving data from datagridview Pin
yazadzhiev29-Feb-08 3:50
memberyazadzhiev29-Feb-08 3:50 
GeneralRe: Problem with receiving data from datagridview Pin
Duncan Edwards Jones29-Feb-08 10:57
memberDuncan Edwards Jones29-Feb-08 10:57 
GeneralError with DataSet Pin
it-bergmann12-Dec-07 2:32
memberit-bergmann12-Dec-07 2:32 
GeneralRe: Error with DataSet Pin
it-bergmann12-Dec-07 5:06
memberit-bergmann12-Dec-07 5:06 
QuestionColumn Head and Margins Pin
craver8411-Nov-07 8:56
membercraver8411-Nov-07 8:56 
GeneralPrint Option Dialog Pin
luckydyno10-Nov-07 2:16
memberluckydyno10-Nov-07 2:16 
GeneralRe: Print Option Dialog Pin
Duncan Edwards Jones11-Nov-07 1:26
memberDuncan Edwards Jones11-Nov-07 1:26 
GeneralPrint Dataset tables Pin
Yaswan25-Oct-07 3:23
memberYaswan25-Oct-07 3:23 
GeneralRe: Print Dataset tables Pin
Duncan Edwards Jones25-Oct-07 3:36
memberDuncan Edwards Jones25-Oct-07 3:36 
GeneralRe: Print Dataset tables Pin
Yaswan25-Oct-07 3:39
memberYaswan25-Oct-07 3:39 
GeneralPrint preview show and print a different info Pin
edwarmartinez1-Sep-07 16:58
memberedwarmartinez1-Sep-07 16:58 
GeneralRe: Print preview show and print a different info Pin
Duncan Edwards Jones3-Sep-07 5:43
memberDuncan Edwards Jones3-Sep-07 5:43 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150520.1 | Last Updated 6 Apr 2006
Article Copyright 2005 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid