用于打印和打印预览 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类作为网格数据源


