Print Preview and Print DataGridView

DRGAGI 146 Reputation points
2020-12-07T19:18:34.223+00:00

I have DataGridView with a database attached, is there any way to print data from it with print preview?

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,644 questions
0 comments No comments
{count} votes

Accepted answer
  1. Anonymous
    2020-12-07T19:53:28.317+00:00

    Hi
    Here is an example to show some aspects of printing a DataGridView. Attributes shown in comments.

    This is just an example and bears no relationship to reality, and has not had extensive testing. Seems to work reasonably well.

    Anyway, you probably don't need some of the features in this example, but, the printing routines may be useful. The reference links in the comments may be useful too.

    ' DGV MULTIPAGE PRINT WITH
    ' RIGHTTOLEFT TOGGLE
    
    ' Form1 with Label1 for Header Text
    ' blank DataGridView called DGV
    ' Button1 (Page Settings Dialog)
    ' Button2 (Print - Skip Printer settings)
    ' Button3 (Print Preview)
    ' Button4 (Print - using Printer settings)
    ' Button5 to choose Grid Font
    ' CheckBox1 (toggle Right to Left Printing)
    ' Label2  (Landscape ON/OFF indicator)
    
    ' adjust row header column with
    ' mouse to suit requirements.
    
    'modified code using:
    ' https://code.msdn.microsoft.com/windowsdesktop/VBNet-Printing-Example-bc3b0176
    ' and .............. for RIGHT TO LEFT
    ' https://stackoverflow.com/questions/40010705/printing-datagridview-from-right-to-left
    
    Option Strict On
    Option Explicit On
    Public Class Form1
    
        Class pageDetails
            Property columns As Integer
            Property rows As Integer
            Property startCol As Integer
            Property startRow As Integer
        End Class
    
        Dim pages As Dictionary(Of Integer, pageDetails)
    
        ' define colors for Headers
        Dim HeaderBackCol As Color = SystemColors.ControlLight
        Dim HeaderForeCol As New SolidBrush(Color.Black)
    
        Dim maxPagesWide As Integer
        Dim maxPagesTall As Integer
    
        Dim dt As New DataTable("Freddy")
        Dim dataPath As String = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "MyData.xml")
        Dim MySetPath As String = IO.Path.Combine(Application.StartupPath, "MySettings.txt")
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            ' uncomment to save data on app close
            '   dt.WriteXml(dataPath, XmlWriteMode.WriteSchema)
    
            With PrintDocument1
                Using sw As New IO.StreamWriter(MySetPath)
                    sw.WriteLine(.DefaultPageSettings.Margins.Left.ToString)
                    sw.WriteLine(.DefaultPageSettings.Margins.Right.ToString)
                    sw.WriteLine(.DefaultPageSettings.Margins.Top.ToString)
                    sw.WriteLine(.DefaultPageSettings.Margins.Bottom.ToString)
                    sw.WriteLine(CheckBox1.Checked)
                    sw.WriteLine(PrintDialog1.PrinterSettings.DefaultPageSettings.Landscape)
                End Using
            End With
        End Sub
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            ' get data from file if it exists
            ' otherwise create some test data
            If IO.File.Exists(dataPath) Then
                dt.ReadXml(dataPath)
            Else
                For c As Integer = 1 To 9
                    dt.Columns.Add("Column" & c.ToString)
                Next
                For r As Integer = 1 To 120
                    Dim fmt As String = "R{0}  C{1}"
                    dt.Rows.Add(
                        String.Format(fmt, r, 1), String.Format(fmt, r, 2), String.Format(fmt, r, 3), String.Format(fmt, r, 4), String.Format(fmt, r, 5), String.Format(fmt, r, 6), String.Format(fmt, r, 7), String.Format(fmt, r, 8), String.Format(fmt, r, 9))
                Next
            End If
    
            ' set a few of the DGV properties
            With DGV
                .DataSource = dt
                .DefaultCellStyle.Font = New Font("Microsoft Sans Serif", 12)
                .EnableHeadersVisualStyles = False
                With .RowHeadersDefaultCellStyle
                    .BackColor = HeaderBackCol
                    .ForeColor = HeaderForeCol.Color
                End With
                With .ColumnHeadersDefaultCellStyle
                    .BackColor = HeaderBackCol
                    .ForeColor = HeaderForeCol.Color
                    .Padding = New Padding(12, 0, 12, 0)
                End With
                .ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize
                .AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells
                .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.ColumnHeader
            End With
    
            ' this is to  try to workaround a
            ' silly bug in the Margins settings
            PageSetupDialog1.EnableMetric = True
    
            ' reload some settings
            ' Margins, Landscape, RightToLeft
            If IO.File.Exists(MySetPath) Then
                With PrintDocument1
                    Using sr As New IO.StreamReader(MySetPath)
                        Try
                            With .DefaultPageSettings
                                .Margins.Left = CInt(sr.ReadLine())
                                .Margins.Right = CInt(sr.ReadLine())
                                .Margins.Top = CInt(sr.ReadLine())
                                .Margins.Bottom = CInt(sr.ReadLine())
                                CheckBox1.Checked = CBool(sr.ReadLine())
                                .Landscape = CBool(sr.ReadLine())
                            End With
    
                            If .DefaultPageSettings.Landscape Then
                                Label2.Text = "Landscape is ON"
                            Else
                                Label2.Text = "Landscape is OFF"
                            End If
                        Catch ex As Exception
                            MessageBox.Show("Error in Setting file - solution: delete file" & vbCrLf & MySetPath)
                        End Try
                    End Using
                End With
            End If
    
            SetRTL()
        End Sub
        Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
    
            pages = New Dictionary(Of Integer, pageDetails)
    
            Dim pageCounter As Integer = 0
            pages.Add(pageCounter, New pageDetails)
            Dim columnCounter As Integer = 0
            Dim TotalDGVWidth As Integer = 0
            Dim maxWidth As Integer = 0
            Dim maxHeight As Integer = 0
    
            With PrintDocument1
                .OriginAtMargins = True
                maxWidth = .DefaultPageSettings.Bounds.Width - .DefaultPageSettings.Margins.Left - .DefaultPageSettings.Margins.Right
                maxHeight = .DefaultPageSettings.Bounds.Height - .DefaultPageSettings.Margins.Top - .DefaultPageSettings.Margins.Bottom - Label1.Height
            End With
    
            For c As Integer = 0 To DGV.Columns.Count - 1
                If TotalDGVWidth + DGV.RowHeadersWidth + DGV.Columns(c).Width < maxWidth Then
                    TotalDGVWidth += DGV.Columns(c).Width
                    columnCounter += 1
                Else
                    pages(pageCounter) = New pageDetails With {.columns = columnCounter, .rows = 0, .startCol = pages(pageCounter).startCol}
                    TotalDGVWidth += DGV.Columns(c).Width
    
                    TotalDGVWidth = DGV.RowHeadersWidth + DGV.Columns(c).Width
                    columnCounter = 1
                    pageCounter += 1
                    pages.Add(pageCounter, New pageDetails With {.startCol = c})
                End If
                If c = DGV.Columns.Count - 1 Then
                    If pages(pageCounter).columns = 0 Then
                        pages(pageCounter) = New pageDetails With {.columns = columnCounter, .rows = 0, .startCol = pages(pageCounter).startCol}
                    End If
                End If
            Next
    
            maxPagesWide = pages.Keys.Max + 1
            pageCounter = 0
            Dim rowCounter As Integer = 0
            Dim rowSum As Integer = DGV.ColumnHeadersHeight
    
            For r As Integer = 0 To DGV.Rows.Count - 2
                If rowSum + DGV.Rows(r).Height < maxHeight Then
                    rowSum += DGV.Rows(r).Height
                    rowCounter += 1
                Else
                    pages(pageCounter) = New pageDetails With {.columns = pages(pageCounter).columns, .rows = rowCounter, .startCol = pages(pageCounter).startCol, .startRow = pages(pageCounter).startRow}
                    For x As Integer = 1 To maxPagesWide - 1
                        pages(pageCounter + x) = New pageDetails With {.columns = pages(pageCounter + x).columns, .rows = rowCounter, .startCol = pages(pageCounter + x).startCol, .startRow = pages(pageCounter).startRow}
                    Next
    
                    pageCounter += maxPagesWide
                    For x As Integer = 0 To maxPagesWide - 1
                        pages.Add(pageCounter + x, New pageDetails With {.columns = pages(x).columns, .rows = 0, .startCol = pages(x).startCol, .startRow = r})
                    Next
    
                    rowSum = DGV.ColumnHeadersHeight + DGV.Rows(r).Height
                    rowCounter = 1
                End If
                If r = DGV.Rows.Count - 2 Then
                    For x As Integer = 0 To maxPagesWide - 1
                        If pages(pageCounter + x).rows = 0 Then
                            pages(pageCounter + x) = New pageDetails With {.columns = pages(pageCounter + x).columns, .rows = rowCounter, .startCol = pages(pageCounter + x).startCol, .startRow = pages(pageCounter + x).startRow}
                        End If
                    Next
                End If
            Next
    
            maxPagesTall = pages.Count \ maxPagesWide
    
        End Sub
        Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    
            Dim rect As New Rectangle(20, 20, CInt(e.MarginBounds.Width), Label1.Height)
            Dim sf As New StringFormat
            sf.Alignment = StringAlignment.Center
            sf.LineAlignment = StringAlignment.Center
    
            sf.FormatFlags = sf.FormatFlags Or StringFormatFlags.DirectionRightToLeft
    
            e.Graphics.DrawString(Label1.Text, Label1.Font, Brushes.Black, rect, sf)
    
            sf.Alignment = StringAlignment.Center
    
            Dim startX As Integer = e.PageSettings.Margins.Left
            Dim startY As Integer = rect.Bottom
            Static startPage As Integer = 0
            For p As Integer = startPage To pages.Count - 1
                Dim cell As New Rectangle(startX, startY, DGV.RowHeadersWidth, DGV.ColumnHeadersHeight)
                cell = GetRTLCoordinates(rect, cell)
                e.Graphics.FillRectangle(New SolidBrush(HeaderBackCol), cell)
                e.Graphics.DrawRectangle(Pens.Black, cell)
    
                startY += DGV.ColumnHeadersHeight
    
                For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
                    cell = New Rectangle(startX, startY, DGV.RowHeadersWidth, DGV.Rows(r).Height)
                    cell = GetRTLCoordinates(rect, cell)
                    e.Graphics.FillRectangle(New SolidBrush(HeaderBackCol), cell)
                    e.Graphics.DrawRectangle(Pens.Black, cell)
                    e.Graphics.DrawString(DGV.Rows(r).HeaderCell.Value.ToString, DGV.DefaultCellStyle.Font, HeaderForeCol, cell, sf)
                    startY += DGV.Rows(r).Height
                Next
    
                startX += cell.Width
                startY = rect.Bottom
    
                For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
                    cell = New Rectangle(startX, startY, DGV.Columns(c).Width, DGV.ColumnHeadersHeight)
                    cell = GetRTLCoordinates(rect, cell)
                    e.Graphics.FillRectangle(New SolidBrush(HeaderBackCol), cell)
                    e.Graphics.DrawRectangle(Pens.Black, cell)
                    e.Graphics.DrawString(DGV.Columns(c).HeaderCell.Value.ToString, DGV.ColumnHeadersDefaultCellStyle.Font, HeaderForeCol, cell, sf)
                    startX += DGV.Columns(c).Width
                Next
    
                startY = rect.Bottom + DGV.ColumnHeadersHeight
    
                For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
                    startX = e.PageSettings.Margins.Left + DGV.RowHeadersWidth
                    For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
                        cell = New Rectangle(startX, startY, DGV.Columns(c).Width, DGV.Rows(r).Height)
                        cell = GetRTLCoordinates(rect, cell)
                        e.Graphics.DrawRectangle(Pens.Black, cell)
                        e.Graphics.DrawString(DGV(c, r).Value.ToString, DGV.DefaultCellStyle.Font, Brushes.Black, cell, sf)
                        startX += DGV.Columns(c).Width
                    Next
                    startY += DGV.Rows(r).Height
                Next
    
                If p <> pages.Count - 1 Then
                    startPage = p + 1
                    e.HasMorePages = True
                    Return
                Else
                    startPage = 0
                End If
            Next
        End Sub
        Public Function GetRTLCoordinates(container As Rectangle, drawRectangle As Rectangle) As Rectangle
            If Not CheckBox1.Checked Then
                Return drawRectangle
            End If
    
            Return New Rectangle(container.Width - drawRectangle.Width - drawRectangle.X,
                    drawRectangle.Y, drawRectangle.Width, drawRectangle.Height)
        End Function
        Sub Renumber()
    
            With DGV
                ' adds ID number to Row Headers
                Dim c As Integer = 1
                For Each r As DataGridViewRow In .Rows
                    r.HeaderCell.Value = c.ToString.PadLeft(c.ToString.Length)
                    c += 1
                Next
                .RowHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.TopRight
                .RowHeadersDefaultCellStyle.Font = New Font(.DefaultCellStyle.Font.FontFamily, .DefaultCellStyle.Font.SizeInPoints, FontStyle.Bold)
                .RowHeadersWidth = 30 + TextRenderer.MeasureText(c.ToString, .Font).Width
            End With
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ' PAGE SETTINGS
            PageSetupDialog1.ShowDialog()
            If PrintDocument1.DefaultPageSettings.Landscape Then
                Label2.Text = "Landscape is ON"
            Else
                Label2.Text = "Landscape is OFF"
            End If
        End Sub
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            ' DIRECT PRINT
            PrintDocument1.Print()
        End Sub
        Private Sub Button3_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button3.Click
            ' PREVIEW
            With PrintPreviewDialog1
                .Size = New Size(850, 500)
                .PrintPreviewControl.Zoom = 1.0
                .ShowDialog()
            End With
        End Sub
        Private Sub Button4_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button4.Click
            ' PRINT DIALOG
            With PrintDialog1
                .AllowSomePages = True
                .AllowCurrentPage = True
                .AllowSelection = True
                .AllowPrintToFile = True
                .ShowNetwork = True
            End With
            If PrintDialog1.ShowDialog() = DialogResult.OK Then
                PrintDocument1.Print()
            End If
        End Sub
        Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
            SetRTL()
        End Sub
        Sub SetRTL()
            If CheckBox1.Checked Then
                DGV.RightToLeft = RightToLeft.Yes
            Else
                DGV.RightToLeft = RightToLeft.No
            End If
            Renumber()
        End Sub
        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
            DGV.DefaultCellStyle.Font = Choosefont(DGV.DefaultCellStyle.Font)
        End Sub
        Public Function Choosefont(ByVal fon As Font) As Font
            Dim c As New FontDialog()
            c.Font = fon
            c.ShowApply = False
            c.ShowEffects = False
            c.ShowHelp = False
            Try
                If (c.ShowDialog() = DialogResult.OK) Then Return c.Font
            Catch ex As Exception
                MessageBox.Show("Sorry, that font isn't supported.", "Selected font is not a True Type Font", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1)
            End Try
            Return fon
        End Function
    End Class
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful