通过选择列和行打印DataGridView






4.85/5 (99投票s)
一篇关于 DataGrdView 打印的文章。
引言
有时,用户需要打印 DataGridView
中的特定列和行(或全部)。一些情况可能如下所示:
DataGridView
中有太多行,没有必要打印所有行。- 列宽总和可能大于页面宽度,最好在打印时删除一列或多列。
因此,实现了一个名为 PrintDGV
的类,可以在任何 .NET2.0 应用程序中使用。我已经在 C# 和 VB.NET 中 为 DataGrid 和 DataGridView
实现了它。
描述
代码的主要部分是 PrintDGV
类和 PrintOptions
窗体。
在 PrintDGV
中,我们有:
SelectedColumns
和AvailableColumns
列表,用于保存列名。- 一个名为
PrintDoc
的PrintDocument
对象(具有BeginPrint
和PrintPage
事件处理程序) - 四个函数:
Print_DataGridView
:可以从类外部调用的主函数。PrintDoc_BeginPrint
:初始化一些变量以开始打印。PrintDoc_PrintPage
:执行打印工作。DrawFooter
:写入页码。
该代码具有以下特点:
- 支持
TextBox
、Link
、Button
、ComboBox
、CheckBox
和Image
列。 - 绘制列以适应页面宽度,或按照显示的列进行绘制。
- 如果单元格宽度小于其内容,则换行单元格文本。
- 在页面上绘制页脚、日期、时间和标题。
使用代码
要在应用程序中使用该代码,必须将 PrintDGV
类和 PrintOptions
窗体添加到其中,然后调用函数 Print_DataGridView
。在我们的示例中,示例项目有一个名为 MainForm
的 Form
。
在 MainForm
中,DataGridView
填充了 'Persongs.mdb' 的 'Persons' 表。
在 PrintOption
窗体中,用户可以选择 DataGridView
列、适应页面和标题。
PrintDoc_PrintPage
事件处理程序执行以下任务:
- 计算列宽。
- 打印当前页面,逐行打印 - 循环遍历
DataGridView
中的所有行。 - 在“打印选定行”模式下,如果未选择当前行,则跳过它。
- 如果到达页面末尾,则写入页码并转到下一页。如果未到达页面末尾,则:
- 如果在新页面中,则绘制标题、日期-时间、页眉和列(检查是否已由用户选择每个列,如果未选择,则跳过它)。
- 绘制
TextBox
、Link
、Button
、CheckBox
、ComboBox
和Image
单元格的列内容(检查是否已由用户选择每个列,如果未选择,则跳过它)。 - 绘制边框。
- 计算第一页的“每页行数”。
- 写入页脚(页码)。
private static void PrintDoc_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
int tmpWidth, i;
int tmpTop = e.MarginBounds.Top;
int tmpLeft = e.MarginBounds.Left;
int HeaderHeight=0;
try
{
// Before starting first page, it saves
// Width & Height of Headers and CoulmnType
if (PageNo == 1)
{
foreach (DataGridViewColumn GridCol in dgv.Columns)
{
if (!GridCol.Visible) continue;
// Skip if the current column not selected
if (!PrintDGV.SelectedColumns.Contains(
GridCol.HeaderText)) continue;
// Detemining whether the columns
// are fitted to the page or not.
if (FitToPageWidth)
tmpWidth = (int)(Math.Floor((double)(
(double)GridCol.Width /
(double)TotalWidth * (double)TotalWidth *
((double)e.MarginBounds.Width /
(double)TotalWidth))));
else
tmpWidth = GridCol.Width;
HeaderHeight =
(int)(e.Graphics.MeasureString(GridCol.HeaderText,
GridCol.InheritedStyle.Font, tmpWidth).Height) + 11;
// Save width & height of headres and ColumnType
ColumnLefts.Add(tmpLeft);
ColumnWidths.Add(tmpWidth);
ColumnTypes.Add(GridCol.GetType());
tmpLeft += tmpWidth;
}
}
// Printing Current Page, Row by Row
while (RowPos <= dgv.Rows.Count - 1)
{
DataGridViewRow GridRow = dgv.Rows[RowPos];
if (GridRow.IsNewRow || (!PrintAllRows && !GridRow.Selected))
{
RowPos++;
continue;
}
CellHeight = GridRow.Height;
if (tmpTop + CellHeight >=
e.MarginBounds.Height + e.MarginBounds.Top)
{
DrawFooter(e, RowsPerPage);
NewPage = true;
PageNo++;
e.HasMorePages = true;
return;
}
else
{
if (NewPage)
{
// Draw Print Title
e.Graphics.DrawString(PrintTitle,
new Font(dgv.Font, FontStyle.Bold),
Brushes.Black, e.MarginBounds.Left,
e.MarginBounds.Top -
e.Graphics.MeasureString(PrintTitle,
new Font(dgv.Font,
FontStyle.Bold),
e.MarginBounds.Width).Height - 13);
String s = DateTime.Now.ToLongDateString() + " " +
DateTime.Now.ToShortTimeString();
// Draw Time and Date
e.Graphics.DrawString(s,
new Font(dgv.Font, FontStyle.Bold),
Brushes.Black, e.MarginBounds.Left +
(e.MarginBounds.Width -
e.Graphics.MeasureString(s, new Font(dgv.Font,
FontStyle.Bold), e.MarginBounds.Width).Width),
e.MarginBounds.Top -
e.Graphics.MeasureString(PrintTitle,
new Font(new Font(dgv.Font,
FontStyle.Bold), FontStyle.Bold),
e.MarginBounds.Width).Height - 13);
// Draw Headers
tmpTop = e.MarginBounds.Top;
i = 0;
foreach (DataGridViewColumn GridCol in dgv.Columns)
{
if (!GridCol.Visible) continue;
if (!PrintDGV.SelectedColumns.Contains(
GridCol.HeaderText))
continue;
e.Graphics.FillRectangle(new
SolidBrush(Color.LightGray),
new Rectangle((int) ColumnLefts[i], tmpTop,
(int)ColumnWidths[i], HeaderHeight));
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int) ColumnLefts[i], tmpTop,
(int)ColumnWidths[i], HeaderHeight));
e.Graphics.DrawString(GridCol.HeaderText,
GridCol.InheritedStyle.Font,
new SolidBrush(GridCol.InheritedStyle.ForeColor),
new RectangleF((int)ColumnLefts[i], tmpTop,
(int)ColumnWidths[i], HeaderHeight), StrFormat);
i++;
}
NewPage = false;
tmpTop += HeaderHeight;
}
// Draw Columns Contents
i = 0;
foreach (DataGridViewCell Cel in GridRow.Cells)
{
if (!Cel.OwningColumn.Visible) continue;
if (!SelectedColumns.Contains(
Cel.OwningColumn.HeaderText))
continue;
// For the TextBox Column
if (((Type) ColumnTypes[i]).Name ==
"DataGridViewTextBoxColumn" ||
((Type) ColumnTypes[i]).Name ==
"DataGridViewLinkColumn")
{
e.Graphics.DrawString(Cel.Value.ToString(),
Cel.InheritedStyle.Font,
new SolidBrush(Cel.InheritedStyle.ForeColor),
new RectangleF((int)ColumnLefts[i],
(float)tmpTop,
(int)ColumnWidths[i],
(float)CellHeight), StrFormat);
}
// For the Button Column
else if (((Type) ColumnTypes[i]).Name ==
"DataGridViewButtonColumn")
{
CellButton.Text = Cel.Value.ToString();
CellButton.Size = new Size((int)ColumnWidths[i],
CellHeight);
Bitmap bmp = new Bitmap(CellButton.Width,
CellButton.Height);
CellButton.DrawToBitmap(bmp, new Rectangle(0, 0,
bmp.Width, bmp.Height));
e.Graphics.DrawImage(bmp,
new Point((int)ColumnLefts[i], tmpTop));
}
// For the CheckBox Column
else if (((Type) ColumnTypes[i]).Name ==
"DataGridViewCheckBoxColumn")
{
CellCheckBox.Size = new Size(14, 14);
CellCheckBox.Checked = (bool)Cel.Value;
Bitmap bmp = new Bitmap((int)ColumnWidths[i],
CellHeight);
Graphics tmpGraphics = Graphics.FromImage(bmp);
tmpGraphics.FillRectangle(Brushes.White,
new Rectangle(0, 0,
bmp.Width, bmp.Height));
CellCheckBox.DrawToBitmap(bmp,
new Rectangle((int)((bmp.Width -
CellCheckBox.Width) / 2),
(int)((bmp.Height - CellCheckBox.Height) / 2),
CellCheckBox.Width, CellCheckBox.Height));
e.Graphics.DrawImage(bmp,
new Point((int)ColumnLefts[i], tmpTop));
}
// For the ComboBox Column
else if (((Type) ColumnTypes[i]).Name ==
"DataGridViewComboBoxColumn")
{
CellComboBox.Size = new Size((int)ColumnWidths[i],
CellHeight);
Bitmap bmp = new Bitmap(CellComboBox.Width,
CellComboBox.Height);
CellComboBox.DrawToBitmap(bmp, new Rectangle(0, 0,
bmp.Width, bmp.Height));
e.Graphics.DrawImage(bmp,
new Point((int)ColumnLefts[i], tmpTop));
e.Graphics.DrawString(Cel.Value.ToString(),
Cel.InheritedStyle.Font,
new SolidBrush(Cel.InheritedStyle.ForeColor),
new RectangleF((int)ColumnLefts[i] + 1,
tmpTop, (int)ColumnWidths[i]
- 16, CellHeight), StrFormatComboBox);
}
// For the Image Column
else if (((Type) ColumnTypes[i]).Name ==
"DataGridViewImageColumn")
{
Rectangle CelSize = new Rectangle((int)ColumnLefts[i],
tmpTop, (int)ColumnWidths[i], CellHeight);
Size ImgSize = ((Image)(Cel.FormattedValue)).Size;
e.Graphics.DrawImage((Image)Cel.FormattedValue,
new Rectangle((int)ColumnLefts[i] +
(int)((CelSize.Width - ImgSize.Width) / 2),
tmpTop + (int)((CelSize.Height -
ImgSize.Height) / 2),
((Image)(Cel.FormattedValue)).Width,
((Image)(Cel.FormattedValue)).Height));
}
// Drawing Cells Borders
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int)ColumnLefts[i],
tmpTop, (int)ColumnWidths[i], CellHeight));
i++;
}
tmpTop += CellHeight;
}
RowPos++;
// For the first page it calculates Rows per Page
if (PageNo == 1) RowsPerPage++;
}
if (RowsPerPage == 0) return;
// Write Footer (Page Number)
DrawFooter(e, RowsPerPage);
e.HasMorePages = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
历史
修复了两个错误 (2007 年 2 月 22 日)
- C# 代码中的页数是错误的。
- 对于第一页之后的页面,列标题覆盖了第一行(C# 代码和 VB 代码中都是如此)。