Kenth Joshua Espina
Kenth Joshua Espina

Reputation: 87

Exporting DataGridView to PDF Error

I'm having a problem here regarding code I saw posted here: How to print datagridview table with its header in vb.net?

I'm testing without a printer and just saving it as a .pdf file, but it doesn't export the DataGridView. Can anyone help me? What could be the problem?

As you can see, it is visible in Print Preview:

enter image description here

After I save as pdf (because I don't have printer available to test with): enter image description here

My code:

 Private mRow As Integer = 0
    Private newpage As Boolean = True
    Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    Dim rect As New Rectangle(12, 9, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width), lblCurriculumName.Height)
    Dim sf As New StringFormat
    sf.Alignment = StringAlignment.Center
    sf.LineAlignment = StringAlignment.Center
    e.Graphics.DrawString(lblCurriculumName.Text, lblCurriculumName.Font, Brushes.Black, rect, sf)
    sf.Alignment = StringAlignment.Center

    Dim rect1 As New Rectangle(97, 60, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width), txtFullName.Height)
    Dim sf1 As New StringFormat
    sf1.Alignment = StringAlignment.Near
    sf1.LineAlignment = StringAlignment.Near
    e.Graphics.DrawString(txtFullName.Text, txtFullName.Font, Brushes.Black, rect1, sf1)
    sf1.Alignment = StringAlignment.Center

    ' sets it to show '...' for long text
    Dim fmt As StringFormat = New StringFormat(StringFormatFlags.LineLimit)
    fmt.LineAlignment = StringAlignment.Center
    fmt.Trimming = StringTrimming.EllipsisCharacter
    Dim y As Int32 = e.MarginBounds.Top
    Dim rc As Rectangle
    Dim x As Int32
    Dim h As Int32 = 0
    Dim row As DataGridViewRow

    ' print the header text for a new page
    '   use a grey bg just like the control
    If newpage Then
        row = DataGridView1.Rows(mRow)
        x = e.MarginBounds.Left
        For Each cell As DataGridViewCell In row.Cells
            ' since we are printing the control's view,
            ' skip invidible columns
            If cell.Visible Then
                rc = New Rectangle(x, y, cell.Size.Width, cell.Size.Height)

                e.Graphics.FillRectangle(Brushes.LightGray, rc)
                e.Graphics.DrawRectangle(Pens.Black, rc)

                ' reused in the data pront - should be a function
                Select Case DataGridView1.Columns(cell.ColumnIndex).DefaultCellStyle.Alignment
                    Case DataGridViewContentAlignment.BottomRight,
                         DataGridViewContentAlignment.MiddleRight
                        fmt.Alignment = StringAlignment.Far
                        rc.Offset(-1, 0)
                    Case DataGridViewContentAlignment.BottomCenter,
                        DataGridViewContentAlignment.MiddleCenter
                        fmt.Alignment = StringAlignment.Center
                    Case Else
                        fmt.Alignment = StringAlignment.Near
                        rc.Offset(2, 0)
                End Select

                e.Graphics.DrawString(DataGridView1.Columns(cell.ColumnIndex).HeaderText,
                                           DataGridView1.Font, Brushes.Black, rc, fmt)
                x += rc.Width
                h = Math.Max(h, rc.Height)
            End If
        Next
        y += h

    End If
    newpage = False

    ' now print the data for each row
    Dim thisNDX As Int32
    For thisNDX = mRow To DataGridView1.RowCount - 1
        ' no need to try to print the new row
        If DataGridView1.Rows(thisNDX).IsNewRow Then Exit For

        row = DataGridView1.Rows(thisNDX)
        x = e.MarginBounds.Left
        h = 0

        ' reset X for data
        x = e.MarginBounds.Left

        ' print the data
        For Each cell As DataGridViewCell In row.Cells
            If cell.Visible Then
                rc = New Rectangle(x, y, cell.Size.Width, cell.Size.Height)

                ' pick up any RowPrePaint rule
                If Convert.ToString(row.Cells(2).Value.ToString) = "NG" Then
                    Using br As New SolidBrush(Color.MistyRose)
                        e.Graphics.FillRectangle(br, rc)
                    End Using
                End If

                e.Graphics.DrawRectangle(Pens.Black, rc)

                Select Case DataGridView1.Columns(cell.ColumnIndex).DefaultCellStyle.Alignment
                    Case DataGridViewContentAlignment.BottomRight,
                         DataGridViewContentAlignment.MiddleRight
                        fmt.Alignment = StringAlignment.Far
                        rc.Offset(-1, 0)
                    Case DataGridViewContentAlignment.BottomCenter,
                        DataGridViewContentAlignment.MiddleCenter
                        fmt.Alignment = StringAlignment.Center
                    Case Else
                        fmt.Alignment = StringAlignment.Near
                        rc.Offset(2, 0)
                End Select

                e.Graphics.DrawString(cell.FormattedValue.ToString(),
                                     DataGridView1.Font, Brushes.Black, rc, fmt)

                x += rc.Width
                h = Math.Max(h, rc.Height)
            End If


        Next
        y += h
        ' next row to print
        mRow = thisNDX + 1

        If y + h > e.MarginBounds.Bottom Then
            e.HasMorePages = True
            mRow -= 1   'causes last row to rePrint on next page
            newpage = True
            Return
        End If
    Next

End Sub

Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click

    'need to start fresh each time
    mRow = 0
    newpage = True

    PrintPreviewDialog1.Document = PrintDocument1
    'optionally reset the first page shown
    PrintPreviewDialog1.PrintPreviewControl.StartPage = 0
    PrintPreviewDialog1.WindowState = FormWindowState.Maximized
    PrintPreviewDialog1.ShowDialog()

End Sub

Upvotes: 2

Views: 734

Answers (1)

Once the document has printed as a Preview, if you decide to print, the document has to be printed again. This means all that code in PrintDocument1_PrintPage has to run again, this time sending the output to the printer.

However, at the end of the Preview, mRow will be the max number of DGV rows and newpage is false so it appears there is nothing to print. The solution is to initialize those in the BeginPrint event:

Private Sub PrintDocument1_BeginPrint(sender As Object, 
               e As PrintEventArgs) Handles PrintDocument1.BeginPrint
    mRow = 0
    newpage = True
    PrintPreviewDialog1.PrintPreviewControl.StartPage = 0
    PrintPreviewDialog1.PrintPreviewControl.Zoom = 1.0
End Sub

Now, when printing starts again for the printer, they are set to process the entire document. The code also resets the first page to show and the initial Zoom.

Upvotes: 2

Related Questions