Rabeea qabaha Rabeea qabaha - 1 month ago 21
Vb.net Question

Printing DataGridView from Right to Left

I'm new in printing in vb.net, what I want to do is printing

DataGridView
items
I searched online for code and I found this source from MSDN, the code work perfect but what I want is printing the
DataGridView
from Right to left, how can I do this.
thanks.

This is the source code which I get from Printing DataGridView Example:

Public Class Form1

''' <summary>
''' structire to hold printed page details
''' </summary>
''' <remarks></remarks>
Private Structure pageDetails
Dim columns As Integer
Dim rows As Integer
Dim startCol As Integer
Dim startRow As Integer
End Structure
''' <summary>
''' dictionary to hold printed page details, with index key
''' </summary>
''' <remarks></remarks>
Private pages As Dictionary(Of Integer, pageDetails)

Dim maxPagesWide As Integer
Dim maxPagesTall As Integer

''' <summary>
''' this just loads some text values into the dgv
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.RowHeadersWidth = CInt(DataGridView1.RowHeadersWidth * 1.35)
For r As Integer = 1 To 100
Dim y As Integer = r
Dim fmt As String = "R{0}C{1}"
DataGridView1.Rows.Add()
DataGridView1.Rows(r - 1).SetValues(Enumerable.Range(1, 10).Select(Function(x) String.Format(fmt, y, x)).ToArray)
DataGridView1.Rows(r - 1).HeaderCell.Value = r.ToString
Next
End Sub

''' <summary>
''' shows a PrintPreviewDialog
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub btnPreview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPreview.Click
Dim ppd As New PrintPreviewDialog
ppd.Document = PrintDocument1
ppd.WindowState = FormWindowState.Maximized
ppd.ShowDialog()
End Sub

''' <summary>
''' starts print job
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub btnPrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPrint.Click
PrintDocument1.Print()
End Sub

''' <summary>
''' the majority of this Sub is calculating printed page ranges
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
''this removes the printed page margins
PrintDocument1.OriginAtMargins = True
PrintDocument1.DefaultPageSettings.Margins = New Drawing.Printing.Margins(0, 0, 0, 0)

pages = New Dictionary(Of Integer, pageDetails)

Dim maxWidth As Integer = CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width) - 40
Dim maxHeight As Integer = CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Height) - 40 + Label1.Height

Dim pageCounter As Integer = 0
pages.Add(pageCounter, New pageDetails)

Dim columnCounter As Integer = 0

Dim columnSum As Integer = DataGridView1.RowHeadersWidth

For c As Integer = 0 To DataGridView1.Columns.Count - 1
If columnSum + DataGridView1.Columns(c).Width < maxWidth Then
columnSum += DataGridView1.Columns(c).Width
columnCounter += 1
Else
pages(pageCounter) = New pageDetails With {.columns = columnCounter, .rows = 0, .startCol = pages(pageCounter).startCol}
columnSum = DataGridView1.RowHeadersWidth + DataGridView1.Columns(c).Width
columnCounter = 1
pageCounter += 1
pages.Add(pageCounter, New pageDetails With {.startCol = c})
End If
If c = DataGridView1.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 = DataGridView1.ColumnHeadersHeight

For r As Integer = 0 To DataGridView1.Rows.Count - 2
If rowSum + DataGridView1.Rows(r).Height < maxHeight Then
rowSum += DataGridView1.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 = DataGridView1.ColumnHeadersHeight + DataGridView1.Rows(r).Height
rowCounter = 1
End If
If r = DataGridView1.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

''' <summary>
''' this is the actual printing routine.
''' using the pagedetails i calculated earlier, it prints a title,
''' + as much of the datagridview as will fit on 1 page, then moves to the next page.
''' this is setup to be dynamic. try resizing the dgv columns or rows
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim rect As New Rectangle(20, 20, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width), Label1.Height)
Dim sf As New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center

e.Graphics.DrawString(Label1.Text, Label1.Font, Brushes.Black, rect, sf)

sf.Alignment = StringAlignment.Near

Dim startX As Integer = 50
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, DataGridView1.RowHeadersWidth, DataGridView1.ColumnHeadersHeight)
e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
e.Graphics.DrawRectangle(Pens.Black, cell)

startY += DataGridView1.ColumnHeadersHeight

For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
cell = New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.Rows(r).Height)
e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
e.Graphics.DrawRectangle(Pens.Black, cell)
e.Graphics.DrawString(DataGridView1.Rows(r).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
startY += DataGridView1.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, DataGridView1.Columns(c).Width, DataGridView1.ColumnHeadersHeight)
e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
e.Graphics.DrawRectangle(Pens.Black, cell)
e.Graphics.DrawString(DataGridView1.Columns(c).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
startX += DataGridView1.Columns(c).Width
Next

startY = rect.Bottom + DataGridView1.ColumnHeadersHeight

For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
startX = 50 + DataGridView1.RowHeadersWidth
For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.Rows(r).Height)
e.Graphics.DrawRectangle(Pens.Black, cell)
e.Graphics.DrawString(DataGridView1(c, r).Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
startX += DataGridView1.Columns(c).Width
Next
startY += DataGridView1.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

End Class

Answer

To make that printing RTL, you need to make some changes in the posted code

  1. You should use a StringFormat having StringFormatFlags.DirectionRightToLeft format glag.
  2. Also instead of drawing rectangles from left to right, you should correct coordinates to support drawing from right to left.

To solve the first issue, it's enough to add the mentioned flag to the string format:

sf.FormatFlags = sf.FormatFlags Or StringFormatFlags.DirectionRightToLeft

To solve the second issue, you should create such method:

Public Function GetRTLCoordinates(container As Rectangle, drawRectangle As Rectangle) _
    As Rectangle
    Return New Rectangle(container.Width - drawRectangle.Width - drawRectangle.X, _
        drawRectangle.Y, drawRectangle.Width, drawRectangle.Height)
End Function

Then in the code, after each line of code which calculated a rectangle named cell, add this line of code:

cell = GetRTLCoordinates(rect, cell)

Code

Here is the changed version of PrintDocument1_PrintPage method. Don't forget to copy GetRTLCoordinates method which is mentioned above.

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    Dim rect As New Rectangle(20, 20, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.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.Near

    Dim startX As Integer = 50
    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, DataGridView1.RowHeadersWidth, DataGridView1.ColumnHeadersHeight)
        cell = GetRTLCoordinates(rect, cell)
        e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
        e.Graphics.DrawRectangle(Pens.Black, cell)

        startY += DataGridView1.ColumnHeadersHeight

        For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
            cell = New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.Rows(r).Height)
            cell = GetRTLCoordinates(rect, cell)
            e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
            e.Graphics.DrawRectangle(Pens.Black, cell)
            e.Graphics.DrawString(DataGridView1.Rows(r).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
            startY += DataGridView1.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, DataGridView1.Columns(c).Width, DataGridView1.ColumnHeadersHeight)
            cell = GetRTLCoordinates(rect, cell)
            e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
            e.Graphics.DrawRectangle(Pens.Black, cell)
            e.Graphics.DrawString(DataGridView1.Columns(c).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
            startX += DataGridView1.Columns(c).Width
        Next

        startY = rect.Bottom + DataGridView1.ColumnHeadersHeight

        For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
            startX = 50 + DataGridView1.RowHeadersWidth
            For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
                cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.Rows(r).Height)
                cell = GetRTLCoordinates(rect, cell)
                e.Graphics.DrawRectangle(Pens.Black, cell)
                e.Graphics.DrawString(DataGridView1(c, r).Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
                startX += DataGridView1.Columns(c).Width
            Next
            startY += DataGridView1.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
Comments