如何实现DataGridView多页打印?解决单页数据溢出问题
DataGridView 多页打印解决方案
你当前的代码直接将整个DataGridView转为Bitmap缩印,既无法处理超出单页的内容,还通过e.HasMorePages = false强制关闭了多页打印。要实现正确的多页打印,需要逐行计算每页可容纳的内容,分批次绘制,并通过HasMorePages控制分页流程。
实现步骤与代码修改
- 添加类级变量跟踪当前打印行索引
- 在
PrintPage事件中逐页绘制表头与数据行 - 动态计算每页可打印行数,判断是否需要继续分页
完整代码如下:
// 类级变量,跟踪当前打印到第几行 private int currentPrintRow = 0; private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { // 获取打印区域的边界 var printArea = e.MarginBounds; // 定义行高、表头高度(可根据实际调整) int rowHeight = dataGridView1.RowTemplate.Height; int headerHeight = dataGridView1.ColumnHeadersHeight; // 计算每页可打印的数据行数(减去表头占用的高度) int rowsPerPage = (printArea.Height - headerHeight) / rowHeight; if (rowsPerPage <= 0) rowsPerPage = 1; // 绘制表头 DrawHeader(e.Graphics, printArea, headerHeight); // 绘制当前页的数据行 int endRow = currentPrintRow + rowsPerPage; if (endRow > dataGridView1.Rows.Count) endRow = dataGridView1.Rows.Count; DrawDataRows(e.Graphics, printArea, headerHeight, rowHeight, currentPrintRow, endRow); // 更新当前行索引,判断是否还有更多页 currentPrintRow = endRow; e.HasMorePages = currentPrintRow < dataGridView1.Rows.Count; } // 绘制表头方法 private void DrawHeader(Graphics g, Rectangle printArea, int headerHeight) { float x = printArea.Left; float y = printArea.Top; // 绘制表头背景 g.FillRectangle(Brushes.LightGray, new RectangleF(x, y, printArea.Width, headerHeight)); // 绘制每列表头 foreach (DataGridViewColumn col in dataGridView1.Columns) { if (!col.Visible) continue; // 绘制单元格边框 g.DrawRectangle(Pens.Black, x, y, col.Width, headerHeight); // 绘制表头文本 g.DrawString(col.HeaderText, dataGridView1.Font, Brushes.Black, new RectangleF(x + 2, y + 2, col.Width - 4, headerHeight - 4), new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); x += col.Width; } } // 绘制数据行方法 private void DrawDataRows(Graphics g, Rectangle printArea, int headerHeight, int rowHeight, int startRow, int endRow) { float y = printArea.Top + headerHeight; for (int i = startRow; i < endRow; i++) { DataGridViewRow row = dataGridView1.Rows[i]; if (row.IsNewRow) continue; float x = printArea.Left; // 绘制行背景(交替行颜色) Brush rowBrush = (i % 2 == 0) ? Brushes.White : Brushes.LightBlue; g.FillRectangle(rowBrush, new RectangleF(x, y, printArea.Width, rowHeight)); foreach (DataGridViewCell cell in row.Cells) { if (!cell.OwningColumn.Visible) continue; // 绘制单元格边框 g.DrawRectangle(Pens.Black, x, y, cell.OwningColumn.Width, rowHeight); // 绘制单元格文本 g.DrawString(cell.Value?.ToString() ?? "", dataGridView1.Font, Brushes.Black, new RectangleF(x + 2, y + 2, cell.OwningColumn.Width - 4, rowHeight - 4), new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center }); x += cell.OwningColumn.Width; } y += rowHeight; } } private void button3_Click(object sender, EventArgs e) { try { printDocument1.DefaultPageSettings.Landscape = true; dataGridView1.ClearSelection(); // 重置打印行索引 currentPrintRow = 0; printPreviewDialog1.Document = printDocument1; printPreviewDialog1.PrintPreviewControl.Zoom = 1; printPreviewDialog1.ShowDialog(); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
关键说明
currentPrintRow变量:每次打印前重置为0,打印过程中记录当前已打印到的行,用于判断是否需要继续分页。- 表头重复绘制:通过
DrawHeader方法确保每页顶部都显示表头,提升可读性。 - 行高与列宽适配:直接使用DataGridView的行高和列宽,避免缩放导致的字体模糊问题。
- 交替行颜色:可选优化,让打印内容更易读。
- 可见列判断:跳过隐藏列,保证打印内容与界面一致。
内容的提问来源于stack exchange,提问作者John B
相关产品推荐
相关产品推荐

