用于打印和打印预览 DataGrid 或 DataGridView 控件的类






4.76/5 (34投票s)
一个可以添加到应用程序中的类,用于从 DataGrid 生成格式精美的打印件。
引言
System.Windows.Forms.DataGrid
控件是 .NET 工具库中最强大且最常用的控件之一,而这个类 (DataGridPrinter
) 增加了功能,允许您从数据网格中生成打印件和打印预览,采用整洁且可自定义的布局。
要绘制网格,首先绘制一个正方形
绘制 datagrid
时的基本操作是绘制一个矩形并在其中填充文本。 为此,我有一个名为 DrawCellString
的单个子程序,它根据传入的对齐方式和格式参数在单元格内绘制一个 string
。
Public Function DrawCellString(ByVal s As String, _
ByVal HorizontalAlignment As CellTextHorizontalAlignment, _
ByVal VerticalAlignment As CellTextVerticalAlignment, _
ByVal BoundingRect As Rectangle, _
ByVal DrawRectangle As Boolean, _
ByVal Target As Graphics, _
ByVal PrintFont As Font)
Dim x As Single, y As Single
If DrawRectangle Then
Target.DrawRectangle(_GridPen, BoundingRect)
End If
'\\ Set the text alignment
If HorizontalAlignment =
CellTextHorizontalAlignment.LeftAlign Then
_Textlayout.Alignment = StringAlignment.Near
ElseIf HorizontalAlignment =
CellTextHorizontalAlignment.RightAlign _
Then
_Textlayout.Alignment = StringAlignment.Far
Else
_Textlayout.Alignment = StringAlignment.Center
End If
Dim BoundingRectF As New RectangleF(BoundingRect.X + _CellGutter, _
BoundingRect.Y + _CellGutter, _
BoundingRect.Width - (2 * _CellGutter), _
BoundingRect.Height - (2 * _CellGutter))
Target.DrawString(s, PrintFont, System.Drawing.Brushes.Black, _
BoundingRectF, _Textlayout)
End Function
有两个类级别变量用于定义如何绘制单元格:CellGutter
指定 string
边界框边缘与 GridPen
之间的边距(以像素为单位),而 GridPen
是用于绘制框的笔。
现在你可以画一个盒子,你可以画一行
为了打印网格,您需要打印两种类型的行:列标题行和数据行。 此类始终以一列列标题开始每个新页面。
Private Sub PrintGridHeaderLine(ByVal e As _
System.Drawing.Printing.PrintPageEventArgs)
Dim Top As Double = _PageContentRectangle.Top
Dim Bottom As Double = Top + _Rowheight + (2 * _CellGutter)
Top = RoundTo(Top, 2)
Bottom = RoundTo(Bottom, 2)
Dim nColumn As Integer
For nColumn = 0 To GridColumnCount() - 1
Dim rcCell As New Rectangle(_ColumnBounds(nColumn).Left, Top, _
_ColumnBounds(nColumn).Width, Bottom - Top)
Call DrawCellString(GetColumnHeadingText(nColumn), _
CellTextHorizontalAlignment.CentreAlign, _
CellTextVerticalAlignment.MiddleAlign, _
rcCell, True, e.Graphics, _PrintFont)
Next
End Sub
这非常简单。 唯一棘手的部分是从 datagrid
获取列的标题,方法如下:
Private Function GetColumnHeadingText(ByVal Column As Integer) As String
If TypeOf _DataGrid.DataSource Is DataTable Then
Return CType(_DataGrid.DataSource, _
DataTable).Columns(Column).ToString
ElseIf TypeOf _DataGrid.DataSource Is DataSet Then
Return CType(_DataGrid.DataSource, DataSet).Tables( _
_DataGrid.DataMember).Columns(Column).ToString
ElseIf TypeOf _DataGrid.DataSource Is DataView Then
Return CType(_DataGrid.DataSource, _
DataView).Table.Columns(Column).ToString
Else
'TODO : Get the column caption....
End If
End Function
为了打印一行数据,我们使用当前行的行内容执行相同的操作
Private Sub PrintGridLine(ByVal e As _
System.Drawing.Printing.PrintPageEventArgs, _
ByVal RowNumber As Integer)
Dim RowFromTop As Integer = RowNumber + 1 - _CurrentPrintGridLine
Dim Top As Double = _PageContentRectangle.Top + (RowFromTop * _
((_CellGutter * 2) + _Rowheight))
Dim Bottom As Double = Top + _Rowheight + (2 * _CellGutter)
Top = RoundTo(Top, 2)
Bottom = RoundTo(Bottom, 2)
Dim Items() As Object
If TypeOf _DataGrid.DataSource Is DataTable Then
Items = CType(_DataGrid.DataSource, _
System.Data.DataTable).DefaultView.Item(_
RowNumber - 1).Row.ItemArray
ElseIf TypeOf _DataGrid.DataSource Is DataSet Then
Items = CType(_DataGrid.DataSource, _
System.Data.DataSet).Tables( _
_DataGrid.DataMember).DefaultView.Item(_
RowNumber - 1).Row.ItemArray
ElseIf TypeOf _DataGrid.DataSource Is DataView Then
Items = CType(_DataGrid.DataSource, _
System.Data.DataView).Table.DefaultView.Item( _
RowNumber - 1).Row.ItemArray
Else
'TODO : Get the content for the current row from the data
' source ....
End If
Dim nColumn As Integer
For nColumn = 0 To Items.Length - 1
Dim rcCell As New Rectangle(_ColumnBounds(nColumn).Left, Top,_
_ColumnBounds(nColumn).Width, Bottom - Top)
Call DrawCellString(Items(nColumn).ToString, _
CellTextHorizontalAlignment.CentreAlign, _
CellTextVerticalAlignment.MiddleAlign, _
rcCell, True, e.Graphics, _PrintFont)
Next
End Sub
将所有内容放到一个页面上
打印页面分为三个区域:页眉、正文和页脚。 还有一个 InterSectionSpacing
属性,用于指定各部分之间的间隙。 这些都表示为页面高度的百分比,将任何一个设置为零将省略该部分。
正文部分是从页面高度的剩余部分计算出来的,当页眉、页脚和部分间距相加后,这用于计算每个页面上可能容纳的行数
Private Function RowsPerPage(ByVal GridLineFont As Font, _
ByVal e As Graphics) As Integer
Return (_PageContentRectangle.Height / _
((_CellGutter * 2) + _Rowheight)) - 2
End Function
更改网格外观的设置
可以使用 HeaderPen
、FooterPen
和 GridPen
属性分别设置各部分周围线条的颜色和宽度。
可以使用 HeaderFont
、FooterFont
和 PrintFont
属性分别设置每个部分的字体。
使用该类预览和打印 DataGrid
如果您在窗体上有一个 datagrid
,并且想要使用此类预览和选择性地打印它,您可以将 System.Windows.Forms.PrintPreviewDialog
添加到您的窗体和一个打印菜单,并添加以下代码
Private GridPrinter As DataGridPrinter
Private Sub MenuItem_File_print_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles MenuItem_File_print.Click
If GridPrinter Is Nothing Then
GridPrinter = New DataGridPrinter(Me.DataGrid1)
End If
With GridPrinter
.HeaderText = "Some text"
.HeaderHeightPercent = 10
.FooterHeightPercent = 5
.InterSectionSpacingPercent = 2
'\\ Set any other properties to
'affect the look of the grid...
End With
With Me.PrintPreviewDialog1
.Document = GridPrinter.PrintDocument
If .ShowDialog = DialogResult.OK Then
GridPrinter.Print()
End If
End With
End Sub
如果您希望使用更新的 DataGridView
控件而不是 DataGrid
控件,则有一个构造函数可以将它作为参数。 其他一切都以相同的方式工作。
历史
- 2006-04-06:创建
- 2016-01-24:添加了构造函数/代码以使用
DataGridView
类作为网格数据源