在 DotNet Framework 上打印 DataGridView






4.71/5 (24投票s)
此库在 .NET Framework 3.5 中提供 DataGridView 打印功能(C# VB F#)。
GridDrawer.Net
目录
演示
DataGridView 控件是一个非常有用的工具,可以以表格格式显示数据。然而,该控件并未内置打印方法,这使得开发人员需要创建或设计一种方法来轻松打印 DataGridView 的内容。
DataDrawer 是一个类 DLL,可以轻松提供 DataGridView 打印功能。该库是用 C# 编写的,有一个针对 .NET 3.5 的版本,集成了 LINQ,还有一个 .NET 2.0 版本。该库支持 C++、C#、VB.NET 和 F# 开发环境。

引言
类库 DLL 为开发人员提供了一种无缝的方法来实现 DataGridView 打印。
DLL 实现了以下功能:- 按级别或列打印
- 打印选定的行或列
- 将分区居中到打印纸上
- 页码
- 优化的 DataGridViewTextBoxCell 打印
- 如 DataGridView 控件所示的自动换行和单元格大小
- 利用 .NET Framework 3.5 的强大功能。也提供 .NET 2.0 版本。
- 提供缩放调整以强制列适应单张纸
- 可选的页眉、页脚和标题块打印
- 自包含的库,方便开发人员使用
- 兼容 C++、C#、VB.NET 和 F#
代码行
为了使打印作业顺利进行,一个基本思想是在项目中创建一条代码线。
DataGridView 有多个级别,分为多个分区。级别标识可在纸张上打印的行数。分区是可在纸张上打印的列数。
有了这个概念,就可以很容易地进行一些计算,并拥有一组覆盖 DataGridView 的分区。结构
实现
类 DataGridViewExtentions
![]() |
此类实现了打印作业,并为 DataGridView 及其组件添加了功能。 Font、ColumnWidth、HeaderHeight 和 RowHeight 函数有一些重载,它们使用“scale”参数。“scale”参数是“FitColumnsToPage”功能的关键。 代码设计旨在为函数的形式提供统一或相似的方法。 public static Color ForeColor(this DataGridViewCell cell)
{
if (cell.HasStyle && cell.Style.ForeColor != Color.Empty) return cell.Style.ForeColor;
else return cell.InheritedStyle.ForeColor;
}
public static Color BackColor(this DataGridViewCell cell)
{
if (cell.HasStyle && cell.Style.BackColor != Color.Empty) return cell.Style.BackColor;
else return cell.InheritedStyle.BackColor;
}
使用这种编码方法,当不需要时,应最小化初始化样式。请参阅 MSDN 上的 Windows Forms DataGridView 控件中的单元格样式。 |
类 DocumentMetrics
![]() |
用于跟踪文档的可打印坐标; public static DocumentMetrics FromPrintDocument(PrintDocument printDocument)
{
PageSettings pageSettings = printDocument.DefaultPageSettings;
return new DocumentMetrics()
{
Width =
(pageSettings.Landscape)
?pageSettings.PaperSize.Height:pageSettings.PaperSize.Width,
Height =
(pageSettings.Landscape)
?pageSettings.PaperSize.Width:pageSettings.PaperSize.Height,
LeftMargin = pageSettings.Margins.Left,
TopMargin = pageSettings.Margins.Top,
RightMargin = pageSettings.Margins.Right,
BottomMargin = pageSettings.Margins.Bottom
};
}
|
PartitionBounds 类
![]() |
PartitionBounds 类包含从 DataGridView 分割的分区数量的边界,即分区的包含的行和列以及边界的坐标信息(大小)。此类可以命名为 PartitionMetrics,但可能与 DocumentMetrics 混淆。 |
Partition 类
![]() |
Partition 类表示可在单张纸上打印的 DataGridView 的部分。 // code showing how rows are returned by this class
public DataGridViewRow GetRow(int i)
{
return GridView.Rows[Bounds.StartRowIndex + i];
}
public IEnumerable
|
PrintBlock 抽象类

此类将标题、页眉和页脚的打印与库隔离开来。
GridDrawer 中定义了 3 个 PrintBlock 对象:TitlePrintBlock、SheetFooter 和 SheetHeader。
这些 PrintBlock 对象是通过扩展 PrintBlock 类来定义的。
下面描述了使用此库实现标题、页眉和页脚打印的方法。首先调用 GetSize 方法,该方法设置一个 Rectangle,Draw 方法将在其中进行打印。这使我们能够定义一些要打印的块,而无需修改库核心。

Draw 函数接收一个 Dictionary 参数,其中包含有关页码、总页数、日期和时间的 CodeEnum 枚举信息。
注意。 Lib.GridDraw.Tools 中已实现一个可重用的 TitlePrintBlock 类。有关详细信息,请参阅“使用此库”部分。
public class TitlePrintBlock : PrintBlock
{
public String Title { get; set; }
public Color ForeColor { get; set; }
public Font Font { get; set; }
public StringFormat Format { get; set; }
public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
{
return g.MeasureString(Title, Font, metrics.PrintAbleWidth, Format);
}
public override void Draw(Graphics g, Dictionary codes)
{
g.DrawString(Title, Font, new SolidBrush(ForeColor), Rectangle, Format);
}
}
GridDrawer 类
该库的核心是 GridDrawer 类。GridDrawer 公开了类的属性和方法。使用此类应该非常直接,并且可以轻松地集成到您的代码中。

该类有三个主要轴。
计算分区边界
- 打印文档时的第一步是计算要打印的纸张的分区边界。必须注意标题(第一级)、页眉和页脚的高度。
- 如果将“MustFitColumnsToPage”设置为 true 且列宽大于纸张的可打印宽度,则计算比例。
- 定义必须出现在分区第一行的行。
- 定义必须出现在分区第一列的列。
- 定义一个代码 Dictionary,为标题、页眉和页脚打印、页码、总页数、日期和时间信息设置 PrintBlock 抽象类。
创建分区
所有分区都在单个实例中计算和创建。分区根据初始化过程或步骤中计算的信息进行设置。
绘制纸张
根据分区信息,绘制纸张。- 页眉(可选)
- 标题(可选)
- 分区(列标题和分区的单元格)
- 页脚(可选)
使用库
需要页眉?
创建一个扩展 PrintBlock 类的类,类似于演示项目中包含的类。public class HeaderPrintBlock : PrintBlock
{
float imgHeight = 75;
public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
{
return new SizeF(metrics.PrintAbleWidth, imgHeight + 2); //+2 for spacing with document
}
public override void Draw(System.Drawing.Graphics g, Dictionary codes)
{
GraphicsUnit units = GraphicsUnit.Pixel;
RectangleF rec = Properties.Resources.logo.GetBounds(ref units);
float scale = imgHeight / rec.Height;
// as you can see below, we are using the base.Rectangle.property which has been set by GridDrawer Class
// after it knows The Size of this block.
g.DrawImage(Properties.Resources.logo, new RectangleF(Rectangle.X, Rectangle.Y, rec.Width * scale, imgHeight));
}
}
需要页脚?
创建一个扩展 PrintBlock 类的类,类似于演示项目中包含的类。 public class FooterPrintBlock : PrintBlock
{
Font font = new Font("Tahoma", 9, GraphicsUnit.Point);
public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
{
return g.MeasureString("Page X Of Y", font);
}
public override void Draw(System.Drawing.Graphics g, Dictionary codes)
{
StringFormat format = new StringFormat();
format.Trimming = StringTrimming.Word;
format.FormatFlags = StringFormatFlags.NoWrap;
format.Alignment = StringAlignment.Far;
// as you can see below, we are using the codes param to know on which page we are for instance.
g.DrawString(
string.Format("Page {0} Of {1}", codes[CodeEnum.SheetNumber], codes[CodeEnum.SheetsCount]),
font,
new SolidBrush(Color.Black),
Rectangle,
format);
}
}
需要标题?
初始化 Lib.GridDraw.Tools.TitlePrintBlock.cs 中实现的重用类。TitlePrintBlock titleBlock = new TitlePrintBlock(printDocument.DocumentName,Color.DarkBlue);
最后一步:打印 DataGridView
Lib.GridDraw.Tools.PrintingDataGridViewProvider 类使用 printDocument.PrintPage 事件初始化 printProvider,以管理 DataGridview 的打印。printProvider = Tools.PrintingDataGridViewProvider.Create(
printDocument,
GridView, chkCenter.Checked, chkFitColumns.Checked,
new TitlePrintBlock(printDocument.DocumentName,Color.DarkBlue),
new PrintBlocks.HeaderPrintBlock(),
new PrintBlocks.FooterPrintBlock());
待办事项
按级别打印与按列打印(在 版本 1.0.0.2 的 Change Set 10625 中可用)仅打印选定的行和列(在 版本 1.0.0.3 的 Change Set 10805 中可用)维护 .Net 2 项目(在 版本 1.0.0.3 的 Change Set 10868 中可用)- 为每行提供一个打印块(评论或投票)
- 提供一种广泛的方式来打印每种类型的 DataGridViewCell(评论或投票)
结论
希望您喜欢 GridDraw.NET。请随时提供您的反馈。很高兴能创建并为社区贡献这个项目。
关注点
这是我用 .NET 3.5 和 Linq 编写的第一个项目。理解和使用 Linq 简化了源代码。
谢谢
我谨感谢 Salan Al-Ani 撰写的 CodeProject 文章。
并感谢 codeplex.com 为 GridDrawer 库提供源代码控制功能。
我还要感谢 Marc Miller,他审阅了本文的许多部分并纠正了大部分语法错误。