|
I've used the Another DataGridView Printer[^] class for about a year now. It works very well, but the author's unorthodox coding style makes it difficult to follow.
This class is much cleaner, and also works well.
From what I can see, though, this class lacks in options, like the ability to include a Subtitle, a Footer, Page Numbering, and numerous minor tweaks that the Another DataGridView Printer[^] class offers.
Both versions lack a variable indicating the total number of pages in the document, and therefore the ability to print only select pages from the document. For a lengthy report, partial page printing would be extremely helpful, especially in this environmentally conscious age.
If I get time to look into this, I hope to fix this problem. For now, though, I'm not offering any solutions.
I hope this review helps others and maybe even sparks some interest in further development.
Thanks to both developers for this tool!
Avoid Sears: http://www.joeswelding.biz/Sears
|
|
|
|
|
|
I have 3 small datagridviews on one form. Rather than print each one to a separate page, wasting paper, I'd like to print them on the same page. Can this class be adapted to do that?
|
|
|
|
|
'corregido el error al imprimir más de una hoja
'no error printing 2 or more pages
'###########################################################
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
'Dim more As Boolean = MyDataGridViewPrinter.DrawDataGridView(e.Graphics)
'If more = True Then
' 'If e.HasMorePages = True Then
' e.HasMorePages = True
' 'End If
'End If
e.HasMorePages = MyDataGridViewPrinter.DrawDataGridView(e.Graphics)
End Sub
'###########################################################
Private Sub cmdImprimir_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles cmdImprimir.Click
Dim MyPrintDialog As New PrintDialog()
Dim Centrado As Boolean = True
Dim TieneTitulo As Boolean = True
Dim NumeroPagina As Boolean = False
Dim Titulo As String = "Informacion Mayores Volumenes"
Dim Fuente As New Font("Tahoma", 12, FontStyle.Bold, GraphicsUnit.Point)
Dim ColorTitulo As Color = Color.Black
Dim Margenes As New Margins(20, 20, 20, 20)
MyPrintDialog.AllowCurrentPage = False
MyPrintDialog.AllowPrintToFile = False
MyPrintDialog.AllowSelection = False
MyPrintDialog.AllowSomePages = False
MyPrintDialog.PrintToFile = False
MyPrintDialog.ShowHelp = False
MyPrintDialog.ShowNetwork = False
If MyPrintDialog.ShowDialog() <> DialogResult.OK Then Exit Sub
PrintDocument1.DocumentName = Titulo
PrintDocument1.PrinterSettings = MyPrintDialog.PrinterSettings
PrintDocument1.DefaultPageSettings = MyPrintDialog.PrinterSettings.DefaultPageSettings
PrintDocument1.DefaultPageSettings.Margins = Margenes
MyDataGridViewPrinter = New DataGridViewPrinter(grdInformacionMiembroValor, PrintDocument1, Centrado, TieneTitulo, Titulo, Fuente, ColorTitulo, NumeroPagina)
Dim MyPrintPreviewDialog As New PrintPreviewDialog()
MyPrintPreviewDialog.Document = PrintDocument1
MyPrintPreviewDialog.ShowDialog()
'PrintDocument1.Print()
End Sub
'###########################################################
Imports System.Collections.Generic
Imports System.Drawing.Printing
Public Class DataGridViewprinter
Private TheDataGridView As DataGridView
' The DataGridView Control which will be printed
Private ThePrintDocument As PrintDocument
' The PrintDocument to be used for printing
Private IsCenterOnPage As Boolean
' Determine if the report will be printed in the Top-Center of the page
Private IsWithTitle As Boolean
' Determine if the page contain title text
Private TheTitleText As String
' The title text to be printed in each page (if IsWithTitle is set to true)
Private TheTitleFont As Font
' The font to be used with the title text (if IsWithTitle is set to true)
Private TheTitleColor As Color
' The color to be used with the title text (if IsWithTitle is set to true)
Private IsWithPaging As Boolean
' Determine if paging is used
Dim CurrentRow As Integer
' A static parameter that keep track on which Row (in the DataGridView control) that should be printed
Dim PageNumber As Integer
Private PageWidth As Integer
Private PageHeight As Integer
Private LeftMargin As Integer
Private TopMargin As Integer
Private RightMargin As Integer
Private BottomMargin As Integer
Private CurrentY As Single
' A parameter that keep track on the y coordinate of the page, so the next object to be printed will start from this y coordinate
Private RowHeaderHeight As Single
Private RowsHeight As List(Of Single)
Private ColumnsWidth As List(Of Single)
Private TheDataGridViewWidth As Single
' Maintain a generic list to hold start/stop points for the column printing
' This will be used for wrapping in situations where the DataGridView will not fit on a single page
Private mColumnPoints As List(Of Integer())
Private mColumnPointsWidth As List(Of Single)
Private mColumnPoint As Integer
Private DejaFait As Boolean
' The class constructor
Public Sub New(ByVal aDataGridView As DataGridView, ByVal aPrintDocument As PrintDocument, ByVal CenterOnPage As Boolean, ByVal WithTitle As Boolean, ByVal aTitleText As String, ByVal aTitleFont As Font, _
ByVal aTitleColor As Color, ByVal WithPaging As Boolean)
TheDataGridView = aDataGridView
ThePrintDocument = aPrintDocument
IsCenterOnPage = CenterOnPage
IsWithTitle = WithTitle
TheTitleText = aTitleText
TheTitleFont = aTitleFont
TheTitleColor = aTitleColor
IsWithPaging = WithPaging
PageNumber = 0
RowsHeight = New List(Of Single)()
ColumnsWidth = New List(Of Single)()
mColumnPoints = New List(Of Integer())()
mColumnPointsWidth = New List(Of Single)()
' Claculating the PageWidth and the PageHeight
If Not ThePrintDocument.DefaultPageSettings.Landscape Then
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Width
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Height
Else
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Width
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Height
End If
' Claculating the page margins
LeftMargin = ThePrintDocument.DefaultPageSettings.Margins.Left
TopMargin = ThePrintDocument.DefaultPageSettings.Margins.Top
RightMargin = ThePrintDocument.DefaultPageSettings.Margins.Right
BottomMargin = ThePrintDocument.DefaultPageSettings.Margins.Bottom
' First, the current row to be printed is the first row in the DataGridView control
CurrentRow = 0
End Sub
' The function that calculate the height of each row (including the header row), the width of each column (according to the longest text in all its cells including the header cell), and the whole DataGridView width
Private Sub Calculate(ByVal g As Graphics)
'if (PageNumber == 0) // Just calculate once
If (PageNumber = 0) AndAlso (DejaFait = False) Then
' Just calculate once
'DejaFait = true
Dim tmpSize As New SizeF()
Dim tmpFont As Font
Dim tmpWidth As Single
TheDataGridViewWidth = 0
For i As Integer = 0 To TheDataGridView.Columns.Count - 1
tmpFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font
If tmpFont Is Nothing Then
' If there is no special HeaderFont style, then use the default DataGridView font style
tmpFont = TheDataGridView.DefaultCellStyle.Font
End If
tmpSize = g.MeasureString(TheDataGridView.Columns(i).HeaderText, tmpFont)
tmpWidth = tmpSize.Width
RowHeaderHeight = tmpSize.Height
For j As Integer = 0 To TheDataGridView.Rows.Count - 1
tmpFont = TheDataGridView.Rows(j).DefaultCellStyle.Font
If tmpFont Is Nothing Then
' If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
tmpFont = TheDataGridView.DefaultCellStyle.Font
End If
tmpSize = g.MeasureString("Anything", tmpFont)
RowsHeight.Add(tmpSize.Height)
tmpSize = g.MeasureString(TheDataGridView.Rows(j).Cells(i).EditedFormattedValue.ToString(), tmpFont)
If tmpSize.Width > tmpWidth Then
tmpWidth = tmpSize.Width
End If
Next
If TheDataGridView.Columns(i).Visible Then
TheDataGridViewWidth += tmpWidth
End If
ColumnsWidth.Add(tmpWidth)
Next
' Define the start/stop column points based on the page width and the DataGridView Width
' We will use this to determine the columns which are drawn on each page and how wrapping will be handled
' By default, the wrapping will occurr such that the maximum number of columns for a page will be determine
Dim k As Integer
Dim mStartPoint As Integer = 0
For k = 0 To TheDataGridView.Columns.Count - 1
If TheDataGridView.Columns(k).Visible Then
mStartPoint = k
Exit For
End If
Next
Dim mEndPoint As Integer = TheDataGridView.Columns.Count
For k = TheDataGridView.Columns.Count - 1 To 0 Step -1
If TheDataGridView.Columns(k).Visible Then
mEndPoint = k + 1
Exit For
End If
Next
Dim mTempWidth As Single = TheDataGridViewWidth
Dim mTempPrintArea As Single = CSng(PageWidth) - CSng(LeftMargin) - CSng(RightMargin)
' We only care about handling where the total datagridview width is bigger then the print area
If TheDataGridViewWidth > mTempPrintArea Then
mTempWidth = 0.0F
For k = 0 To TheDataGridView.Columns.Count - 1
If TheDataGridView.Columns(k).Visible Then
mTempWidth += ColumnsWidth(k)
' If the width is bigger than the page area, then define a new column print range
If mTempWidth > mTempPrintArea Then
mTempWidth -= ColumnsWidth(k)
mColumnPoints.Add(New Integer() {mStartPoint, mEndPoint})
mColumnPointsWidth.Add(mTempWidth)
mStartPoint = k
mTempWidth = ColumnsWidth(k)
End If
End If
' Our end point is actually one index above the current index
mEndPoint = k + 1
Next
End If
' Add the last set of columns
mColumnPoints.Add(New Integer() {mStartPoint, mEndPoint})
mColumnPointsWidth.Add(mTempWidth)
'mColumnPoint = 0
End If
End Sub
' The funtion that print the title, page number, and the header row
Private Sub DrawHeader(ByVal g As Graphics)
CurrentY = CSng(TopMargin)
' Printing the page number (if isWithPaging is set to true)
If IsWithPaging Then
PageNumber += 1
Dim PageString As String = "Page " & PageNumber.ToString()
Dim PageStringFormat As New StringFormat()
PageStringFormat.Trimming = StringTrimming.Word
PageStringFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
PageStringFormat.Alignment = StringAlignment.Far
Dim PageStringFont As New Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point)
Dim PageStringRectangle As New RectangleF(CSng(LeftMargin), CurrentY, CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin), g.MeasureString(PageString, PageStringFont).Height)
g.DrawString(PageString, PageStringFont, New SolidBrush(Color.Black), PageStringRectangle, PageStringFormat)
CurrentY += g.MeasureString(PageString, PageStringFont).Height
End If
' Printing the title (if IsWithTitle is set to true)
If IsWithTitle Then
Dim TitleFormat As New StringFormat()
TitleFormat.Trimming = StringTrimming.Word
TitleFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
If IsCenterOnPage Then
TitleFormat.Alignment = StringAlignment.Center
Else
TitleFormat.Alignment = StringAlignment.Near
End If
Dim TitleRectangle As New RectangleF(CSng(LeftMargin), CurrentY, CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin), g.MeasureString(TheTitleText, TheTitleFont).Height)
g.DrawString(TheTitleText, TheTitleFont, New SolidBrush(TheTitleColor), TitleRectangle, TitleFormat)
CurrentY += g.MeasureString(TheTitleText, TheTitleFont).Height
End If
' Calculating the starting x coordinate that the printing process will start from
Dim CurrentX As Single = CSng(LeftMargin)
If IsCenterOnPage Then
CurrentX += ((CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin)) - mColumnPointsWidth(mColumnPoint)) / 2.0F
End If
' Setting the HeaderFore style
Dim HeaderForeColor As Color = TheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor
If HeaderForeColor.IsEmpty Then
' If there is no special HeaderFore style, then use the default DataGridView style
HeaderForeColor = TheDataGridView.DefaultCellStyle.ForeColor
End If
Dim HeaderForeBrush As New SolidBrush(HeaderForeColor)
' Setting the HeaderBack style
Dim HeaderBackColor As Color = TheDataGridView.ColumnHeadersDefaultCellStyle.BackColor
If HeaderBackColor.IsEmpty Then
' If there is no special HeaderBack style, then use the default DataGridView style
HeaderBackColor = TheDataGridView.DefaultCellStyle.BackColor
End If
Dim HeaderBackBrush As New SolidBrush(HeaderBackColor)
' Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
Dim TheLinePen As New Pen(TheDataGridView.GridColor, 1)
' Setting the HeaderFont style
Dim HeaderFont As Font = TheDataGridView.ColumnHeadersDefaultCellStyle.Font
If HeaderFont Is Nothing Then
' If there is no special HeaderFont style, then use the default DataGridView font style
HeaderFont = TheDataGridView.DefaultCellStyle.Font
End If
' Calculating and drawing the HeaderBounds
Dim HeaderBounds As New RectangleF(CurrentX, CurrentY, mColumnPointsWidth(mColumnPoint), RowHeaderHeight)
g.FillRectangle(HeaderBackBrush, HeaderBounds)
' Setting the format that will be used to print each cell of the header row
Dim CellFormat As New StringFormat()
CellFormat.Trimming = StringTrimming.Word
CellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
' Printing each visible cell of the header row
Dim CellBounds As RectangleF
Dim ColumnWidth As Single
For i As Integer = CInt(mColumnPoints(mColumnPoint).GetValue(0)) To CInt(mColumnPoints(mColumnPoint).GetValue(1)) - 1
If Not TheDataGridView.Columns(i).Visible Then
Continue For
End If
' If the column is not visible then ignore this iteration
ColumnWidth = ColumnsWidth(i)
' Check the CurrentCell alignment and apply it to the CellFormat
If TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Right") Then
CellFormat.Alignment = StringAlignment.Far
ElseIf TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Center") Then
CellFormat.Alignment = StringAlignment.Center
Else
CellFormat.Alignment = StringAlignment.Near
End If
CellBounds = New RectangleF(CurrentX, CurrentY, ColumnWidth, RowHeaderHeight)
' Printing the cell text
g.DrawString(TheDataGridView.Columns(i).HeaderText, HeaderFont, HeaderForeBrush, CellBounds, CellFormat)
' Drawing the cell bounds
If TheDataGridView.RowHeadersBorderStyle <> DataGridViewHeaderBorderStyle.None Then
' Draw the cell border only if the HeaderBorderStyle is not None
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowHeaderHeight)
End If
CurrentX += ColumnWidth
Next
CurrentY += RowHeaderHeight
End Sub
' The function that print a bunch of rows that fit in one page
' When it returns true, meaning that there are more rows still not printed, so another PagePrint action is required
' When it returns false, meaning that all rows are printed (the CureentRow parameter reaches the last row of the DataGridView control) and no further PagePrint action is required
Private Function DrawRows(ByVal g As Graphics) As Boolean
' Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
Dim TheLinePen As New Pen(TheDataGridView.GridColor, 1)
' The style paramters that will be used to print each cell
Dim RowFont As Font
Dim RowForeColor As Color
Dim RowBackColor As Color
Dim RowForeBrush As SolidBrush
Dim RowBackBrush As SolidBrush
Dim RowAlternatingBackBrush As SolidBrush
' Setting the format that will be used to print each cell
Dim CellFormat As New StringFormat()
CellFormat.Trimming = StringTrimming.Word
CellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit
' Printing each visible cell
Dim RowBounds As RectangleF
Dim CurrentX As Single
Dim ColumnWidth As Single
While CurrentRow < TheDataGridView.Rows.Count
If TheDataGridView.Rows(CurrentRow).Visible Then
' Print the cells of the CurrentRow only if that row is visible
' Setting the row font style
RowFont = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.Font
If RowFont Is Nothing Then
' If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
RowFont = TheDataGridView.DefaultCellStyle.Font
End If
' Setting the RowFore style
RowForeColor = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.ForeColor
If RowForeColor.IsEmpty Then
' If the there is no special RowFore style of the CurrentRow, then use the default one associated with the DataGridView control
RowForeColor = TheDataGridView.DefaultCellStyle.ForeColor
End If
RowForeBrush = New SolidBrush(RowForeColor)
' Setting the RowBack (for even rows) and the RowAlternatingBack (for odd rows) styles
RowBackColor = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.BackColor
If RowBackColor.IsEmpty Then
' If the there is no special RowBack style of the CurrentRow, then use the default one associated with the DataGridView control
RowBackBrush = New SolidBrush(TheDataGridView.DefaultCellStyle.BackColor)
RowAlternatingBackBrush = New SolidBrush(TheDataGridView.AlternatingRowsDefaultCellStyle.BackColor)
Else
' If the there is a special RowBack style of the CurrentRow, then use it for both the RowBack and the RowAlternatingBack styles
RowBackBrush = New SolidBrush(RowBackColor)
RowAlternatingBackBrush = New SolidBrush(RowBackColor)
End If
' Calculating the starting x coordinate that the printing process will start from
CurrentX = CSng(LeftMargin)
If IsCenterOnPage Then
CurrentX += ((CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin)) - mColumnPointsWidth(mColumnPoint)) / 2.0F
End If
' Calculating the entire CurrentRow bounds
RowBounds = New RectangleF(CurrentX, CurrentY, mColumnPointsWidth(mColumnPoint), RowsHeight(CurrentRow))
' Filling the back of the CurrentRow
If CurrentRow Mod 2 = 0 Then
g.FillRectangle(RowBackBrush, RowBounds)
Else
g.FillRectangle(RowAlternatingBackBrush, RowBounds)
End If
' Printing each visible cell of the CurrentRow
For CurrentCell As Integer = CInt(mColumnPoints(mColumnPoint).GetValue(0)) To CInt(mColumnPoints(mColumnPoint).GetValue(1)) - 1
If Not TheDataGridView.Columns(CurrentCell).Visible Then
Continue For
End If
' If the cell is belong to invisible column, then ignore this iteration
' Check the CurrentCell alignment and apply it to the CellFormat
If TheDataGridView.Columns(CurrentCell).DefaultCellStyle.Alignment.ToString().Contains("Right") Then
CellFormat.Alignment = StringAlignment.Far
ElseIf TheDataGridView.Columns(CurrentCell).DefaultCellStyle.Alignment.ToString().Contains("Center") Then
CellFormat.Alignment = StringAlignment.Center
Else
CellFormat.Alignment = StringAlignment.Near
End If
ColumnWidth = ColumnsWidth(CurrentCell)
Dim CellBounds As New RectangleF(CurrentX, CurrentY, ColumnWidth, RowsHeight(CurrentRow))
' Printing the cell text
g.DrawString(TheDataGridView.Rows(CurrentRow).Cells(CurrentCell).EditedFormattedValue.ToString(), RowFont, RowForeBrush, CellBounds, CellFormat)
' Drawing the cell bounds
If TheDataGridView.CellBorderStyle <> DataGridViewCellBorderStyle.None Then
' Draw the cell border only if the CellBorderStyle is not None
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowsHeight(CurrentRow))
End If
CurrentX += ColumnWidth
Next
CurrentY += RowsHeight(CurrentRow)
' Checking if the CurrentY is exceeds the page boundries
' If so then exit the function and returning true meaning another PagePrint action is required
If CInt(CurrentY) > (PageHeight - TopMargin - BottomMargin) Then
CurrentRow += 1
Return True
End If
End If
CurrentRow += 1
End While
CurrentRow = 0
'mColumnPoint += 1
' Continue to print the next group of columns
'If mColumnPoint = mColumnPoints.Count Then
' Which means all columns are printed
mColumnPoint = 0
Return False
'Else
'Return True
'End If
End Function
' The method that calls all other functions
Public Function DrawDataGridView(ByVal g As Graphics) As Boolean
Try
Calculate(g)
DrawHeader(g)
Dim bContinue As Boolean = DrawRows(g)
'================================
If bContinue = False Then
PageNumber = 0
DejaFait = True
End If
'================================
Return bContinue
Catch ex As Exception
MessageBox.Show("Operation failed: " & ex.Message.ToString(), Application.ProductName & " - Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
Return False
End Try
End Function
End Class
modified on Thursday, March 12, 2009 3:40 PM
|
|
|
|
|
thanks a lot! great code! works very well.
|
|
|
|
|
Thank you! its very good...
|
|
|
|
|
Dear Salan
Can you post a working project of DataGridPrinter Class in VB.NET so we can download and test it?
Thanks
|
|
|
|
|
Hi, thank you very for this class, it works wonders.
However, I am just wondering how I would manage to get the Vertical allignemnt (because I modified the height of the cell) within the cell to be at Center as it is in my dataGridView.
Also, when I go into the preview print window and press print from within there the printouts do not stop coming, it just keeps on printing, any ideas on how I would fix this?
Thank you
A Trujillo
|
|
|
|
|
Hi Salan,
YOU are awesome! what was Uncle Bill thinking NOT to include a Print Method for that control?!!!
BHM
|
|
|
|
|
Thanks for that, very usefull.
Any idea how I can get this to print the datagrdiview in a different position from where it currently prints (top centre page or align left)?
Ie: I would like to first do some "writer.WriteLine("about 10 lines");"and then append this dgv after these lines.... say at the bottom of the page.
Any ideas greatly appreciated
Best wishes
modified on Sunday, January 25, 2009 5:33 AM
|
|
|
|
|
I can use it wery easily, first it showd and printed me a blank page, but the comments helped me.
Thanks
D
|
|
|
|
|
Hi. Simply great article!
But one question... where and how can I set how many collumns will be shown on a page, as i had 14 collumns and it came out on 4 pages. Cant this be printed on just one?
Regards,
Matjaž
|
|
|
|
|
Hi everyone
I just found this piece of code, it looks great ! Just one thing: does it support row headers printing ?
Thanks in advance
|
|
|
|
|
Well since Salan has not been around for a long time now, I figured a workaround:
Dim columnRowHeader As DataGridViewColumn = yourDGV.Columns.Item(yourDGV.ColumnCount - 1).Clone
yourDGV.Columns.Insert(0, columnRowHeader )
For I = 0 To yourDGV.RowCount - 1
Me.yourDGV.Rows(I).Cells.Item(0).Value = Me.yourDGV.Rows(I).HeaderCell.Value
Next
yourDGV.RowHeadersVisible = False
Hope this helps !
|
|
|
|
|
Hi Toumar,
the code that you give cannot solve my problem.the row header is appear but not in its column itself.
this is my gridview..
Fatal Injury Total
Yes 5 1 6
No 2 2 4
Total 7 3 10
when im using your code.the result is like this..
Fatal Injury Total
Yes 5 1
No 2 2
Total 7 3
plz help me on how to the the row header function in order to get the result as above.
thanx in advance.
regards,
musiw.
|
|
|
|
|
Maybe a bit late reply , but can help others who have had the same problem
Put this code at the beggining of the constructor
DataGridViewColumn colhead = (DataGridViewColumn)TheDataGridView.Columns[aDataGridView.Columns.Count - 1].Clone();
colhead.HeaderText = aDataGridView.TopLeftHeaderCell.Value.ToString();
TheDataGridView.Columns.Insert(0, colhead);
for (int i = 0; i < aDataGridView.Rows.Count; i++)
{
TheDataGridView.Rows[i].Cells[0].Value = TheDataGridView.Rows[i].HeaderCell.Value;
}
modified 9-Jul-13 4:48am.
|
|
|
|
|
'#### This code includes the correction I made in my previous post
'#### regarding page numbering.
'#### If you need a component to print labels (not free):
'#### http://www.scmlsoftware.com
'###########################################################
Imports System.Collections.Generic
Imports System.Drawing.Printing
Public Class cDGVprinter
Private TheDataGridView As DataGridView
' The DataGridView Control which will be printed
Private ThePrintDocument As PrintDocument
' The PrintDocument to be used for printing
Private IsCenterOnPage As Boolean
' Determine if the report will be printed in the Top-Center of the page
Private IsWithTitle As Boolean
' Determine if the page contain title text
Private TheTitleText As String
' The title text to be printed in each page (if IsWithTitle is set to true)
Private TheTitleFont As Font
' The font to be used with the title text (if IsWithTitle is set to true)
Private TheTitleColor As Color
' The color to be used with the title text (if IsWithTitle is set to true)
Private IsWithPaging As Boolean
' Determine if paging is used
Dim CurrentRow As Integer
' A static parameter that keep track on which Row (in the DataGridView control) that should be printed
Dim PageNumber As Integer
Private PageWidth As Integer
Private PageHeight As Integer
Private LeftMargin As Integer
Private TopMargin As Integer
Private RightMargin As Integer
Private BottomMargin As Integer
Private CurrentY As Single
' A parameter that keep track on the y coordinate of the page, so the next object to be printed will start from this y coordinate
Private RowHeaderHeight As Single
Private RowsHeight As List(Of Single)
Private ColumnsWidth As List(Of Single)
Private TheDataGridViewWidth As Single
' Maintain a generic list to hold start/stop points for the column printing
' This will be used for wrapping in situations where the DataGridView will not fit on a single page
Private mColumnPoints As List(Of Integer())
Private mColumnPointsWidth As List(Of Single)
Private mColumnPoint As Integer
Private DejaFait As Boolean
' The class constructor
Public Sub New(ByVal aDataGridView As DataGridView, ByVal aPrintDocument As PrintDocument, ByVal CenterOnPage As Boolean, ByVal WithTitle As Boolean, ByVal aTitleText As String, ByVal aTitleFont As Font, _
ByVal aTitleColor As Color, ByVal WithPaging As Boolean)
TheDataGridView = aDataGridView
ThePrintDocument = aPrintDocument
IsCenterOnPage = CenterOnPage
IsWithTitle = WithTitle
TheTitleText = aTitleText
TheTitleFont = aTitleFont
TheTitleColor = aTitleColor
IsWithPaging = WithPaging
PageNumber = 0
RowsHeight = New List(Of Single)()
ColumnsWidth = New List(Of Single)()
mColumnPoints = New List(Of Integer())()
mColumnPointsWidth = New List(Of Single)()
' Claculating the PageWidth and the PageHeight
If Not ThePrintDocument.DefaultPageSettings.Landscape Then
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Width
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Height
Else
PageHeight = ThePrintDocument.DefaultPageSettings.PaperSize.Width
PageWidth = ThePrintDocument.DefaultPageSettings.PaperSize.Height
End If
' Claculating the page margins
LeftMargin = ThePrintDocument.DefaultPageSettings.Margins.Left
TopMargin = ThePrintDocument.DefaultPageSettings.Margins.Top
RightMargin = ThePrintDocument.DefaultPageSettings.Margins.Right
BottomMargin = ThePrintDocument.DefaultPageSettings.Margins.Bottom
' First, the current row to be printed is the first row in the DataGridView control
CurrentRow = 0
End Sub
' The function that calculate the height of each row (including the header row), the width of each column (according to the longest text in all its cells including the header cell), and the whole DataGridView width
Private Sub Calculate(ByVal g As Graphics)
'if (PageNumber == 0) // Just calculate once
If (PageNumber = 0) AndAlso (DejaFait = False) Then
' Just calculate once
'DejaFait = true
Dim tmpSize As New SizeF()
Dim tmpFont As Font
Dim tmpWidth As Single
TheDataGridViewWidth = 0
For i As Integer = 0 To TheDataGridView.Columns.Count - 1
tmpFont = TheDataGridView.ColumnHeadersDefaultCellStyle.Font
If tmpFont Is Nothing Then
' If there is no special HeaderFont style, then use the default DataGridView font style
tmpFont = TheDataGridView.DefaultCellStyle.Font
End If
tmpSize = g.MeasureString(TheDataGridView.Columns(i).HeaderText, tmpFont)
tmpWidth = tmpSize.Width
RowHeaderHeight = tmpSize.Height
For j As Integer = 0 To TheDataGridView.Rows.Count - 1
tmpFont = TheDataGridView.Rows(j).DefaultCellStyle.Font
If tmpFont Is Nothing Then
' If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
tmpFont = TheDataGridView.DefaultCellStyle.Font
End If
tmpSize = g.MeasureString("Anything", tmpFont)
RowsHeight.Add(tmpSize.Height)
tmpSize = g.MeasureString(TheDataGridView.Rows(j).Cells(i).EditedFormattedValue.ToString(), tmpFont)
If tmpSize.Width > tmpWidth Then
tmpWidth = tmpSize.Width
End If
Next
If TheDataGridView.Columns(i).Visible Then
TheDataGridViewWidth += tmpWidth
End If
ColumnsWidth.Add(tmpWidth)
Next
' Define the start/stop column points based on the page width and the DataGridView Width
' We will use this to determine the columns which are drawn on each page and how wrapping will be handled
' By default, the wrapping will occurr such that the maximum number of columns for a page will be determine
Dim k As Integer
Dim mStartPoint As Integer = 0
For k = 0 To TheDataGridView.Columns.Count - 1
If TheDataGridView.Columns(k).Visible Then
mStartPoint = k
Exit For
End If
Next
Dim mEndPoint As Integer = TheDataGridView.Columns.Count
For k = TheDataGridView.Columns.Count - 1 To 0 Step -1
If TheDataGridView.Columns(k).Visible Then
mEndPoint = k + 1
Exit For
End If
Next
Dim mTempWidth As Single = TheDataGridViewWidth
Dim mTempPrintArea As Single = CSng(PageWidth) - CSng(LeftMargin) - CSng(RightMargin)
' We only care about handling where the total datagridview width is bigger then the print area
If TheDataGridViewWidth > mTempPrintArea Then
mTempWidth = 0.0F
For k = 0 To TheDataGridView.Columns.Count - 1
If TheDataGridView.Columns(k).Visible Then
mTempWidth += ColumnsWidth(k)
' If the width is bigger than the page area, then define a new column print range
If mTempWidth > mTempPrintArea Then
mTempWidth -= ColumnsWidth(k)
mColumnPoints.Add(New Integer() {mStartPoint, mEndPoint})
mColumnPointsWidth.Add(mTempWidth)
mStartPoint = k
mTempWidth = ColumnsWidth(k)
End If
End If
' Our end point is actually one index above the current index
mEndPoint = k + 1
Next
End If
' Add the last set of columns
mColumnPoints.Add(New Integer() {mStartPoint, mEndPoint})
mColumnPointsWidth.Add(mTempWidth)
mColumnPoint = 0
End If
End Sub
' The funtion that print the title, page number, and the header row
Private Sub DrawHeader(ByVal g As Graphics)
CurrentY = CSng(TopMargin)
' Printing the page number (if isWithPaging is set to true)
If IsWithPaging Then
PageNumber += 1
Dim PageString As String = "Page " & PageNumber.ToString()
Dim PageStringFormat As New StringFormat()
PageStringFormat.Trimming = StringTrimming.Word
PageStringFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
PageStringFormat.Alignment = StringAlignment.Far
Dim PageStringFont As New Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point)
Dim PageStringRectangle As New RectangleF(CSng(LeftMargin), CurrentY, CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin), g.MeasureString(PageString, PageStringFont).Height)
g.DrawString(PageString, PageStringFont, New SolidBrush(Color.Black), PageStringRectangle, PageStringFormat)
CurrentY += g.MeasureString(PageString, PageStringFont).Height
End If
' Printing the title (if IsWithTitle is set to true)
If IsWithTitle Then
Dim TitleFormat As New StringFormat()
TitleFormat.Trimming = StringTrimming.Word
TitleFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
If IsCenterOnPage Then
TitleFormat.Alignment = StringAlignment.Center
Else
TitleFormat.Alignment = StringAlignment.Near
End If
Dim TitleRectangle As New RectangleF(CSng(LeftMargin), CurrentY, CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin), g.MeasureString(TheTitleText, TheTitleFont).Height)
g.DrawString(TheTitleText, TheTitleFont, New SolidBrush(TheTitleColor), TitleRectangle, TitleFormat)
CurrentY += g.MeasureString(TheTitleText, TheTitleFont).Height
End If
' Calculating the starting x coordinate that the printing process will start from
Dim CurrentX As Single = CSng(LeftMargin)
If IsCenterOnPage Then
CurrentX += ((CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin)) - mColumnPointsWidth(mColumnPoint)) / 2.0F
End If
' Setting the HeaderFore style
Dim HeaderForeColor As Color = TheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor
If HeaderForeColor.IsEmpty Then
' If there is no special HeaderFore style, then use the default DataGridView style
HeaderForeColor = TheDataGridView.DefaultCellStyle.ForeColor
End If
Dim HeaderForeBrush As New SolidBrush(HeaderForeColor)
' Setting the HeaderBack style
Dim HeaderBackColor As Color = TheDataGridView.ColumnHeadersDefaultCellStyle.BackColor
If HeaderBackColor.IsEmpty Then
' If there is no special HeaderBack style, then use the default DataGridView style
HeaderBackColor = TheDataGridView.DefaultCellStyle.BackColor
End If
Dim HeaderBackBrush As New SolidBrush(HeaderBackColor)
' Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
Dim TheLinePen As New Pen(TheDataGridView.GridColor, 1)
' Setting the HeaderFont style
Dim HeaderFont As Font = TheDataGridView.ColumnHeadersDefaultCellStyle.Font
If HeaderFont Is Nothing Then
' If there is no special HeaderFont style, then use the default DataGridView font style
HeaderFont = TheDataGridView.DefaultCellStyle.Font
End If
' Calculating and drawing the HeaderBounds
Dim HeaderBounds As New RectangleF(CurrentX, CurrentY, mColumnPointsWidth(mColumnPoint), RowHeaderHeight)
g.FillRectangle(HeaderBackBrush, HeaderBounds)
' Setting the format that will be used to print each cell of the header row
Dim CellFormat As New StringFormat()
CellFormat.Trimming = StringTrimming.Word
CellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit Or StringFormatFlags.NoClip
' Printing each visible cell of the header row
Dim CellBounds As RectangleF
Dim ColumnWidth As Single
For i As Integer = CInt(mColumnPoints(mColumnPoint).GetValue(0)) To CInt(mColumnPoints(mColumnPoint).GetValue(1)) - 1
If Not TheDataGridView.Columns(i).Visible Then
Continue For
End If
' If the column is not visible then ignore this iteration
ColumnWidth = ColumnsWidth(i)
' Check the CurrentCell alignment and apply it to the CellFormat
If TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Right") Then
CellFormat.Alignment = StringAlignment.Far
ElseIf TheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Center") Then
CellFormat.Alignment = StringAlignment.Center
Else
CellFormat.Alignment = StringAlignment.Near
End If
CellBounds = New RectangleF(CurrentX, CurrentY, ColumnWidth, RowHeaderHeight)
' Printing the cell text
g.DrawString(TheDataGridView.Columns(i).HeaderText, HeaderFont, HeaderForeBrush, CellBounds, CellFormat)
' Drawing the cell bounds
If TheDataGridView.RowHeadersBorderStyle <> DataGridViewHeaderBorderStyle.None Then
' Draw the cell border only if the HeaderBorderStyle is not None
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowHeaderHeight)
End If
CurrentX += ColumnWidth
Next
CurrentY += RowHeaderHeight
End Sub
' The function that print a bunch of rows that fit in one page
' When it returns true, meaning that there are more rows still not printed, so another PagePrint action is required
' When it returns false, meaning that all rows are printed (the CureentRow parameter reaches the last row of the DataGridView control) and no further PagePrint action is required
Private Function DrawRows(ByVal g As Graphics) As Boolean
' Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
Dim TheLinePen As New Pen(TheDataGridView.GridColor, 1)
' The style paramters that will be used to print each cell
Dim RowFont As Font
Dim RowForeColor As Color
Dim RowBackColor As Color
Dim RowForeBrush As SolidBrush
Dim RowBackBrush As SolidBrush
Dim RowAlternatingBackBrush As SolidBrush
' Setting the format that will be used to print each cell
Dim CellFormat As New StringFormat()
CellFormat.Trimming = StringTrimming.Word
CellFormat.FormatFlags = StringFormatFlags.NoWrap Or StringFormatFlags.LineLimit
' Printing each visible cell
Dim RowBounds As RectangleF
Dim CurrentX As Single
Dim ColumnWidth As Single
While CurrentRow < TheDataGridView.Rows.Count
If TheDataGridView.Rows(CurrentRow).Visible Then
' Print the cells of the CurrentRow only if that row is visible
' Setting the row font style
RowFont = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.Font
If RowFont Is Nothing Then
' If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
RowFont = TheDataGridView.DefaultCellStyle.Font
End If
' Setting the RowFore style
RowForeColor = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.ForeColor
If RowForeColor.IsEmpty Then
' If the there is no special RowFore style of the CurrentRow, then use the default one associated with the DataGridView control
RowForeColor = TheDataGridView.DefaultCellStyle.ForeColor
End If
RowForeBrush = New SolidBrush(RowForeColor)
' Setting the RowBack (for even rows) and the RowAlternatingBack (for odd rows) styles
RowBackColor = TheDataGridView.Rows(CurrentRow).DefaultCellStyle.BackColor
If RowBackColor.IsEmpty Then
' If the there is no special RowBack style of the CurrentRow, then use the default one associated with the DataGridView control
RowBackBrush = New SolidBrush(TheDataGridView.DefaultCellStyle.BackColor)
RowAlternatingBackBrush = New SolidBrush(TheDataGridView.AlternatingRowsDefaultCellStyle.BackColor)
Else
' If the there is a special RowBack style of the CurrentRow, then use it for both the RowBack and the RowAlternatingBack styles
RowBackBrush = New SolidBrush(RowBackColor)
RowAlternatingBackBrush = New SolidBrush(RowBackColor)
End If
' Calculating the starting x coordinate that the printing process will start from
CurrentX = CSng(LeftMargin)
If IsCenterOnPage Then
CurrentX += ((CSng(PageWidth) - CSng(RightMargin) - CSng(LeftMargin)) - mColumnPointsWidth(mColumnPoint)) / 2.0F
End If
' Calculating the entire CurrentRow bounds
RowBounds = New RectangleF(CurrentX, CurrentY, mColumnPointsWidth(mColumnPoint), RowsHeight(CurrentRow))
' Filling the back of the CurrentRow
If CurrentRow Mod 2 = 0 Then
g.FillRectangle(RowBackBrush, RowBounds)
Else
g.FillRectangle(RowAlternatingBackBrush, RowBounds)
End If
' Printing each visible cell of the CurrentRow
For CurrentCell As Integer = CInt(mColumnPoints(mColumnPoint).GetValue(0)) To CInt(mColumnPoints(mColumnPoint).GetValue(1)) - 1
If Not TheDataGridView.Columns(CurrentCell).Visible Then
Continue For
End If
' If the cell is belong to invisible column, then ignore this iteration
' Check the CurrentCell alignment and apply it to the CellFormat
If TheDataGridView.Columns(CurrentCell).DefaultCellStyle.Alignment.ToString().Contains("Right") Then
CellFormat.Alignment = StringAlignment.Far
ElseIf TheDataGridView.Columns(CurrentCell).DefaultCellStyle.Alignment.ToString().Contains("Center") Then
CellFormat.Alignment = StringAlignment.Center
Else
CellFormat.Alignment = StringAlignment.Near
End If
ColumnWidth = ColumnsWidth(CurrentCell)
Dim CellBounds As New RectangleF(CurrentX, CurrentY, ColumnWidth, RowsHeight(CurrentRow))
' Printing the cell text
g.DrawString(TheDataGridView.Rows(CurrentRow).Cells(CurrentCell).EditedFormattedValue.ToString(), RowFont, RowForeBrush, CellBounds, CellFormat)
' Drawing the cell bounds
If TheDataGridView.CellBorderStyle <> DataGridViewCellBorderStyle.None Then
' Draw the cell border only if the CellBorderStyle is not None
g.DrawRectangle(TheLinePen, CurrentX, CurrentY, ColumnWidth, RowsHeight(CurrentRow))
End If
CurrentX += ColumnWidth
Next
CurrentY += RowsHeight(CurrentRow)
' Checking if the CurrentY is exceeds the page boundries
' If so then exit the function and returning true meaning another PagePrint action is required
If CInt(CurrentY) > (PageHeight - TopMargin - BottomMargin) Then
CurrentRow += 1
Return True
End If
End If
CurrentRow += 1
End While
CurrentRow = 0
mColumnPoint += 1
' Continue to print the next group of columns
If mColumnPoint = mColumnPoints.Count Then
' Which means all columns are printed
mColumnPoint = 0
Return False
Else
Return True
End If
End Function
' The method that calls all other functions
Public Function DrawDataGridView(ByVal g As Graphics) As Boolean
Try
Calculate(g)
DrawHeader(g)
Dim bContinue As Boolean = DrawRows(g)
'================================
If bContinue = False Then
PageNumber = 0
DejaFait = True
End If
'================================
Return bContinue
Catch ex As Exception
MessageBox.Show("Operation failed: " & ex.Message.ToString(), Application.ProductName & " - Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
Return False
End Try
End Function
End Class
|
|
|
|
|
Hi,
If I do a print preview and click on the print button of the PrintPreviewDialog, the page number is not reset to 1. It keeps on adding the pages. For example if I have 5 pages in the preview and I click on the print button, the printed pages will start at page number 6.
I'm a VB .Net user so it's hard for me to try to correct the problem myself. But if the solution is a matter of only a couple of lines in C#, I'll be able to manage to make that correction.
Thanks for the code.
|
|
|
|
|
Hi,
Well, I found a solution:
1) In class «DataGridViewPrinter» declarations I added:
private bool AlreadyDone;
....
2) In «private void Calculate(Graphics g)» I changed:
if (PageNumber == 0) // Just calculate once
to:
if ((PageNumber == 0) && (AlreadyDone == false ))// Just calculate once
....
3) I changed «public bool DrawDataGridView(Graphics g)» to:
// The method that calls all other functions
public bool DrawDataGridView(Graphics g)
{
try
{
Calculate(g);
DrawHeader(g);
bool bContinue = DrawRows(g);
//================================
if (bContinue == false)
{
PageNumber = 0;
AlreadyDone = true;
}
//================================
return bContinue;
}
catch (Exception ex)
{
MessageBox.Show("Operation failed: " + ex.Message.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
|
|
|
|
|
Someone tried to print when the datasource (for the datagridview) is a LINQtoSQL query?
|
|
|
|
|
Thanks for this code, saved me a lot of time and worked great right from the beginning printing a grid with images.
|
|
|
|
|
I wrote an app to print out db schema information and was wondering how I was going to print the metadata table SqlConnection.GetSchema returns. I just bound it to a DatGridView and referenced an assembly with your code. Flawless. Thanks again.
Bob
|
|
|
|
|
Hey all,
First, let me say thank you for this code! It saved me hours of headaches! My issue is that I have several textboxes, labels, and a 3D Pie Chart I want to print on the same page as the datagrid. However, I have no clue where to even start looking for find the solution to doing this. I looked up the PrintDocument class on MSDN but I didnt really see anything that helped me understand how to do what I am trying to figure out. Anyone care to point me in the right direction?
|
|
|
|
|
This was reported in an earlier post. The solution proposed then is a bit unwieldy. Since the measurestring function already takes into account text with multiple lines all that is necessary is to use the largest value of any cell string height in the row for the row height not just the last one. So for the row header for example rather than
RowHeaderHeight = tmpSize.Height
use
If tmpSize.Height > RowHeaderHeight Then RowHeaderHeight = tmpSize.Height
|
|
|
|
|
I have some questions about your program. So I want to email you.And I want to get your email.Thank you.
|
|
|
|
|