Print

Public Class DataGridViewPrinter

#Region " Variables "
    Private mTheDataGridView As DataGridView
    Private mThePrintDocument As PrintDocument
    Private mIsCenterOnPage As Boolean
    Private mIsWithTitle As Boolean
    Private mTheTitleText As String
    Private mTheTitleFont As Font
    Private mTheTitleColor As Color
    Private mPageWidth As Integer
    Private mPageHeight As Integer
    Private mLeftMargin As Integer
    Private mTopMargin As Integer
    Private mRightMargin As Integer
    Private mBottomMargin As Integer
    Private mCurrentY As Single
    Private mRowHeaderHeight As Single
    Private mRowsHeight As List(Of Single)
    Private mColumnsWidth As List(Of Single)
    Private mTheDataGridViewWidth As Single
    Private mColumnPoints As List(Of Integer())
    Private mColumnPointsWidth As List(Of Single)
    Private mColumnPoint As Integer
    Private mHasCalculated As Boolean
    Private mCurrentRow As Integer
#End Region

#Region " Constructor "
    Public Sub New(ByVal dataGrid As DataGridView, _
                   ByVal printDoc As PrintDocument, _
                   ByVal center As Boolean, _
                   ByVal withTitle As Boolean, _
                   ByVal title As String, _
                   ByVal titleFont As Font, _
                   ByVal titleColor As Color)
        mTheDataGridView = dataGrid
        mThePrintDocument = printDoc
        mIsCenterOnPage = center
        mIsWithTitle = withTitle
        mTheTitleText = title
        mTheTitleFont = titleFont
        mTheTitleColor = titleColor
        mRowsHeight = New List(Of Single)
        mColumnsWidth = New List(Of Single)
        mColumnPoints = New List(Of Integer())
        mColumnPointsWidth = New List(Of Single)

        If Not mThePrintDocument.DefaultPageSettings.Landscape Then
            mPageWidth = mThePrintDocument.DefaultPageSettings.PaperSize.Width
            mPageHeight = mThePrintDocument.DefaultPageSettings.PaperSize.Height
        Else
            mPageHeight = mThePrintDocument.DefaultPageSettings.PaperSize.Width
            mPageWidth = mThePrintDocument.DefaultPageSettings.PaperSize.Height
        End If

        mLeftMargin = mThePrintDocument.DefaultPageSettings.Margins.Left
        mTopMargin = mThePrintDocument.DefaultPageSettings.Margins.Top
        mRightMargin = mThePrintDocument.DefaultPageSettings.Margins.Right
        mBottomMargin = mThePrintDocument.DefaultPageSettings.Margins.Bottom

        mCurrentRow = 0
    End Sub
#End Region

#Region " Public "

#Region " Functions "
    Public Function DrawDataGridView(ByVal g As Graphics) As Boolean
        Calculate(g)
        DrawHeader(g)

        Return DrawRows(g)
    End Function
#End Region

#Region " Subs "
    Public Sub ForceRecalculate()
        mHasCalculated = False
    End Sub
#End Region

#End Region

#Region " Private "

#Region " Functions "
    Private Function DrawRows(ByVal g As Graphics) As Boolean
        Dim theLinePen As New Pen(mTheDataGridView.GridColor, 1)
        Dim rowFont As Font
        Dim rowForeColor As Color
        Dim rowBackColor As Color
        Dim rowForeBrush As SolidBrush
        Dim rowBackBrush As SolidBrush
        Dim rowAlternatingBackBrush As SolidBrush
        Dim rowBounds As RectangleF
        Dim currentX As Single
        Dim columnWidth As Single
        Dim cellFormat As New StringFormat

        cellFormat.Trimming = StringTrimming.Word
        cellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit

        While mCurrentRow < mTheDataGridView.Rows.Count
            If mTheDataGridView.Rows(mCurrentRow).Visible Then
                rowFont = mTheDataGridView.Rows(mCurrentRow).DefaultCellStyle.Font

                If rowFont Is Nothing Then
                    rowFont = mTheDataGridView.DefaultCellStyle.Font
                End If

                rowForeColor = mTheDataGridView.Rows(mCurrentRow).DefaultCellStyle.ForeColor
                If rowForeColor.IsEmpty Then
                    rowForeColor = mTheDataGridView.DefaultCellStyle.ForeColor
                End If

                rowForeBrush = New SolidBrush(rowForeColor)

                rowBackColor = mTheDataGridView.Rows(mCurrentRow).DefaultCellStyle.BackColor
                If rowBackColor.IsEmpty Then
                    rowBackBrush = New SolidBrush(mTheDataGridView.DefaultCellStyle.BackColor)
                    rowAlternatingBackBrush = New SolidBrush(mTheDataGridView.AlternatingRowsDefaultCellStyle.BackColor)
                Else
                    rowBackBrush = New SolidBrush(rowBackColor)
                    rowAlternatingBackBrush = New SolidBrush(rowBackColor)
                End If

                currentX = mLeftMargin
                If mIsCenterOnPage Then
                    currentX += ((mPageWidth - mRightMargin - mLeftMargin) - mColumnPointsWidth(mColumnPoint)) / 2
                End If

                rowBounds = New RectangleF(currentX, _
                                           mCurrentY, _
                                           mColumnPointsWidth(mColumnPoint), _
                                           mRowsHeight(mCurrentRow))
                If (mCurrentRow Mod 2) = 0 Then
                    g.FillRectangle(rowBackBrush, rowBounds)
                Else
                    g.FillRectangle(rowAlternatingBackBrush, rowBounds)
                End If

                For currentCell = mColumnPoints(mColumnPoint)(0) To mColumnPoints(mColumnPoint)(1)
                    If Not mTheDataGridView.Columns(currentCell).Visible Then
                        Continue For
                    End If

                    If mTheDataGridView.Columns(currentCell).DefaultCellStyle.Alignment.ToString.Contains("Right") Then
                        cellFormat.Alignment = StringAlignment.Far
                    ElseIf mTheDataGridView.Columns(currentCell).DefaultCellStyle.Alignment.ToString.Contains("Center") Then
                        cellFormat.Alignment = StringAlignment.Center
                    Else
                        cellFormat.Alignment = StringAlignment.Near
                    End If

                    columnWidth = mColumnsWidth(currentCell)
                    Dim cellBounds As New RectangleF(currentX, mCurrentY, columnWidth, mRowsHeight(mCurrentRow))

                    g.DrawString(mTheDataGridView.Rows(mCurrentRow).Cells(currentCell).EditedFormattedValue.ToString, _
                                 rowFont, _
                                 rowForeBrush, _
                                 cellBounds, _
                                 cellFormat)
                    If mTheDataGridView.CellBorderStyle <> DataGridViewCellBorderStyle.None Then
                        g.DrawRectangle(theLinePen, currentX, mCurrentY, columnWidth, mRowsHeight(mCurrentRow))
                    End If

                    currentX += columnWidth
                Next currentCell

                mCurrentY += mRowsHeight(mCurrentRow)
                If mCurrentY > (mPageHeight - mTopMargin - mBottomMargin) Then
                    mCurrentY += 1
                    Return True
                End If
            End If

            mCurrentRow += 1
        End While

        mCurrentRow = 0
        mColumnPoint += 1

        If mColumnPoint = mColumnPoints.Count Then
            mColumnPoint = 0
            Return False
        Else
            Return True
        End If
    End Function
#End Region

#Region " Subs "
    Private Sub Calculate(ByVal g As Graphics)
        If mHasCalculated Then
            Exit Sub
        End If

        mHasCalculated = True

        Dim tmpSize As New SizeF
        Dim tmpFont As Font
        Dim tmpWidth As Single

        mTheDataGridViewWidth = 0
        For i As Integer = 0 To mTheDataGridView.Columns.Count - 1
            tmpFont = mTheDataGridView.ColumnHeadersDefaultCellStyle.Font
            If tmpFont Is Nothing Then
                tmpFont = mTheDataGridView.DefaultCellStyle.Font
            End If

            tmpSize = g.MeasureString(mTheDataGridView.Columns(i).HeaderText, tmpFont)
            tmpWidth = tmpSize.Width
            mRowHeaderHeight = tmpSize.Height

            For j As Integer = 0 To mTheDataGridView.Rows.Count - 1
                tmpFont = mTheDataGridView.Rows(j).DefaultCellStyle.Font
                If tmpFont Is Nothing Then
                    tmpFont = mTheDataGridView.DefaultCellStyle.Font
                End If

                tmpSize = g.MeasureString("Anything", tmpFont)
                mRowsHeight.Add(tmpSize.Height)

                tmpSize = g.MeasureString(mTheDataGridView.Rows(j).Cells(i).EditedFormattedValue.ToString, tmpFont)
                If tmpSize.Width > tmpWidth Then
                    tmpWidth = tmpSize.Width
                End If
            Next j

            If mTheDataGridView.Columns(i).Visible Then
                mTheDataGridViewWidth += tmpWidth
            End If

            mColumnsWidth.Add(tmpWidth)
        Next i

        Dim startPoint As Integer = 0
        For k As Integer = 0 To mTheDataGridView.Columns.Count - 1
            If mTheDataGridView.Columns(k).Visible Then
                startPoint = k
                Exit For
            End If
        Next k

        Dim endPoint As Integer = mTheDataGridView.Columns.Count
        For k As Integer = mTheDataGridView.Columns.Count - 1 To 0 Step -1
            If mTheDataGridView.Columns(k).Visible Then
                endPoint = k + 1
                Exit For
            End If
        Next k

        tmpWidth = mTheDataGridViewWidth
        Dim tmpPrintArea As Single = mPageWidth - mLeftMargin - mRightMargin

        If mTheDataGridViewWidth > tmpPrintArea Then
            tmpWidth = 0S

            For k As Integer = 0 To mTheDataGridView.Columns.Count - 1
                If mTheDataGridView.Columns(k).Visible Then
                    tmpWidth += mColumnsWidth(k)

                    If tmpWidth > tmpPrintArea Then
                        tmpWidth -= mColumnsWidth(k)
                        mColumnPoints.Add(New Integer() {startPoint, endPoint})
                        mColumnPointsWidth.Add(tmpWidth)
                        startPoint = k
                        tmpWidth = mColumnsWidth(k)
                    End If
                End If

                endPoint = k + 1
            Next k
        End If

        mColumnPoints.Add(New Integer() {startPoint, endPoint})
        mColumnPointsWidth.Add(tmpWidth)
        mColumnPoint = 0
    End Sub

    Private Sub DrawHeader(ByVal g As Graphics)
        mCurrentY = mTopMargin

        If mIsWithTitle Then
            Dim titleFormat As New StringFormat

            titleFormat.Trimming = StringTrimming.Word
            titleFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip

            If mIsCenterOnPage Then
                titleFormat.Alignment = StringAlignment.Center
            Else
                titleFormat.Alignment = StringAlignment.Near
            End If

            Dim titleRectangle As New RectangleF(mLeftMargin, _
                                                 mCurrentY, _
                                                 mPageWidth - mRightMargin - mLeftMargin, _
                                                 g.MeasureString(mTheTitleText, mTheTitleFont).Height)
            g.DrawString(mTheTitleText, _
                         mTheTitleFont, _
                         New SolidBrush(mTheTitleColor), _
                         titleRectangle, _
                         titleFormat)

            mCurrentY += g.MeasureString(mTheTitleText, mTheTitleFont).Height
        End If

        Dim currentX As Single = mLeftMargin

        If mIsCenterOnPage Then
            currentX += ((mPageWidth - mRightMargin - mLeftMargin) - mColumnPointsWidth(mColumnPoint)) / 2.0F
        End If

        Dim headerForeColor As Color = mTheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor
        If headerForeColor.IsEmpty Then
            headerForeColor = mTheDataGridView.DefaultCellStyle.ForeColor
        End If

        Dim headerForeBrush As New SolidBrush(headerForeColor)

        Dim headerBackColor As Color = mTheDataGridView.ColumnHeadersDefaultCellStyle.BackColor
        If headerBackColor.IsEmpty Then
            headerBackColor = mTheDataGridView.DefaultCellStyle.BackColor
        End If

        Dim headerBackBrush As New SolidBrush(headerBackColor)
        Dim theLinePen As New Pen(mTheDataGridView.GridColor, 1)

        Dim headerFont As Font = mTheDataGridView.ColumnHeadersDefaultCellStyle.Font
        If headerFont Is Nothing Then
            headerFont = mTheDataGridView.DefaultCellStyle.Font
        End If

        Dim headerBounds As New RectangleF(currentX, _
                                           mCurrentY, _
                                           mColumnPointsWidth(mColumnPoint), _
                                           mRowHeaderHeight)

        g.FillRectangle(headerBackBrush, headerBounds)

        Dim cellFormat As New StringFormat

        cellFormat.Trimming = StringTrimming.Word
        cellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip

        Dim cellBounds As RectangleF
        Dim columnWidth As Single

        For i As Integer = mColumnPoints(mColumnPoint)(0) To mColumnPoints(mColumnPoint)(1) - 1
            If Not mTheDataGridView.Columns(i).Visible Then
                Continue For
            End If

            columnWidth = mColumnsWidth(i)

            If mTheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString.Contains("Right") Then
                cellFormat.Alignment = StringAlignment.Far
            ElseIf mTheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString.Contains("Center") Then
                cellFormat.Alignment = StringAlignment.Center
            Else
                cellFormat.Alignment = StringAlignment.Near
            End If

            cellBounds = New RectangleF(currentX, mCurrentY, columnWidth, mRowHeaderHeight)

            g.DrawString(mTheDataGridView.Columns(i).HeaderText, headerFont, headerForeBrush, cellBounds, cellFormat)

            If mTheDataGridView.RowHeadersBorderStyle <> DataGridViewHeaderBorderStyle.None Then
                g.DrawRectangle(theLinePen, currentX, mCurrentY, columnWidth, mRowHeaderHeight)
            End If

            currentX += columnWidth
        Next i

        mCurrentY += mRowHeaderHeight
    End Sub
#End Region

#End Region

End Class

<HideModuleName()> _
Public Module DataGridViewPrinterExtension

#Region " DocumentPrintHandler "
    Private Class DocumentPrintHandler

#Region " Variables "
        Private mPrinter As DataGridViewPrinter
        Private mGrid As DataGridView
#End Region

#Region " Constructor "
        Public Sub New(ByVal grid As DataGridView)
            mGrid = grid
        End Sub
#End Region

#Region " Events "
        Private Sub PrintDocument_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
            e.HasMorePages = mPrinter.DrawDataGridView(e.Graphics)
        End Sub
#End Region

#Region " Subs "
        Public Sub Print(ByVal title As String)
            Dim printDocument As New PrintDocument

            Using dlg As New PrintDialog
                dlg.AllowCurrentPage = False
                dlg.AllowPrintToFile = False
                dlg.AllowSelection = False
                dlg.AllowSomePages = False
                dlg.PrintToFile = False
                dlg.ShowHelp = False
                dlg.ShowNetwork = False

                If dlg.ShowDialog <> Windows.Forms.DialogResult.OK Then
                    Exit Sub
                End If

                printDocument.DocumentName = title
                printDocument.PrinterSettings = dlg.PrinterSettings
                printDocument.DefaultPageSettings = dlg.PrinterSettings.DefaultPageSettings
                printDocument.DefaultPageSettings.Margins = New Margins(40, 40, 40, 40)
            End Using

            mPrinter = New DataGridViewPrinter(mGrid, printDocument, True, True, title, New Font("Tahoma", 18, FontStyle.Bold, GraphicsUnit.Point), Color.Black)

            AddHandler printDocument.PrintPage, AddressOf PrintDocument_PrintPage
            printDocument.Print()
            RemoveHandler printDocument.PrintPage, AddressOf PrintDocument_PrintPage
        End Sub
#End Region

    End Class
#End Region

#Region " Extension "
    <Extension()> _
    Public Sub Print(ByVal grid As DataGridView, ByVal title As String)
        Dim dph As New DocumentPrintHandler(grid)

        dph.Print(title)
    End Sub
#End Region

End Module
Example:
DataGridView.Print("TITLE")

Description

DataGridView.Print("TITLE")

Details

Double click on the code to select all.

 

;