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