VB.NET PrintDocument多页打印异常:设置e.HasMorePages=True后无法分页
VB.NET PrintDocument 分页失效问题排查与修复
核心问题分析
你的代码无法触发新页打印,主要是以下几个关键问题导致:
分页状态无法跨页保留
你在PrintPage事件内部声明了ii、grand_total等变量,每次触发新页打印时,这些变量都会被重置为初始值,导致系统无法记住上一页打印到哪一行,每次都从头开始打印数据。分页标记被强制覆盖
循环中设置e.HasMorePages = True后,代码最后又执行了e.HasMorePages = False,直接覆盖了分页指令,系统不会触发下一页打印流程。分页触发逻辑不合理
你的分页条件If page_number > 10 And page_number < 12限制太死,只有打印到第11行时才会尝试分页,而且没有判断是否还有未打印的剩余数据,无法适配多行数据的连续分页需求。GDI+资源未释放
代码中创建的Pen、Font等GDI+对象没有手动释放,长期运行可能导致内存泄漏,影响打印稳定性。
修复后的完整代码
首先,在窗体类的类级别声明需要跨页保留的变量(放在事件方法外面):
' 类级变量,用于跨页保存打印状态 Private ii As Integer = 0 Private grand_total As Double = 0 Private cgst As Double = 0 Private sgst As Double = 0 Private igst As Double = 0
然后修改PrintPage事件处理代码:
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage Dim l, t, right, b As Integer Dim companyName As String = "G.M.Agencies" l = e.MarginBounds.Left t = e.MarginBounds.Top right = e.MarginBounds.Right b = e.MarginBounds.Bottom Dim StringAlignment As New StringFormat() StringAlignment.Alignment = Drawing.StringAlignment.Far Dim formatednumber As String ' 使用Using语句自动释放GDI+资源 Using bor As New Pen(Color.Black, 2) Using nameFont As New Font("Arial", 24, FontStyle.Bold) Using nameFont2 As New Font("Arial", 12, FontStyle.Bold) Dim r As New Rectangle(l - 50, t - 50, right - 10, b - 10) e.Graphics.DrawRectangle(bor, r) ' 绘制卖家名称下方的横线 e.Graphics.DrawLine(bor, l - 50, t + 100, right + 40, t + 100) ' 绘制买卖双方分隔竖线 e.Graphics.DrawLine(bor, right - 350, t - 50, (right - 350), t + 100) ' 绘制商品描述和表头下方的横线 e.Graphics.DrawLine(bor, l - 50, t + 150, right + 40, t + 150) e.Graphics.DrawLine(bor, l - 50, b - 150, right + 40, b - 150) e.Graphics.DrawLine(bor, l - 50, b - 250, right + 40, b - 250) ' 绘制商品详情表格的竖线 e.Graphics.DrawLine(bor, l + 10, t + 100, l + 10, b - 250) e.Graphics.DrawLine(bor, right - 370, t + 100, right - 370, b - 150) e.Graphics.DrawLine(bor, right - 273, t + 100, right - 273, b - 250) e.Graphics.DrawLine(bor, right - 205, t + 100, right - 205, b - 250) e.Graphics.DrawLine(bor, right - 125, t + 100, right - 125, b - 250) e.Graphics.DrawLine(bor, right - 70, t + 100, right - 70, b - 150) ' 打印公司和发票基本信息 e.Graphics.DrawString(companyName, nameFont, Brushes.Black, l - 40, t - 40) e.Graphics.DrawString("Dharapuram", nameFont2, Brushes.Black, l - 40, t) e.Graphics.DrawString("Invoice No", nameFont2, Brushes.Black, l - 40, t + 20) e.Graphics.DrawString("Date", nameFont2, Brushes.Black, l - 40, t + 40) ' 打印表头文本 e.Graphics.DrawString("S.No", nameFont2, Brushes.Black, l - 40, t + 120) e.Graphics.DrawString("Description", nameFont2, Brushes.Black, l + 40, t + 120) e.Graphics.DrawString("HSN Code", nameFont2, Brushes.Black, right - 360, t + 120) e.Graphics.DrawString("GST %", nameFont2, Brushes.Black, right - 270, t + 120) e.Graphics.DrawString("Rate", nameFont2, Brushes.Black, right - 200, t + 120) e.Graphics.DrawString("Qty", nameFont2, Brushes.Black, right - 120, t + 120) e.Graphics.DrawString("Total", nameFont2, Brushes.Black, right - 60, t + 120) ' 打印总计项标签 e.Graphics.DrawString("Grand Total", nameFont2, Brushes.Black, right - 170, b - 180, StringAlignment) e.Graphics.DrawString("Total CGST", nameFont2, Brushes.Black, right - 170, b - 200, StringAlignment) e.Graphics.DrawString("Total SGST", nameFont2, Brushes.Black, right - 170, b - 220, StringAlignment) e.Graphics.DrawString("Total IGST", nameFont2, Brushes.Black, right - 170, b - 240, StringAlignment) End Using End Using End Using ' 打印商品详情 Dim dataGridViewRows As DataGridViewRowCollection = dg_sales_entry.Rows Dim numRows As Integer = dataGridViewRows.Count Dim startY As Integer = t + 170 Dim currentY As Integer = startY Dim page_number As Integer = 0 e.HasMorePages = False ' 默认无更多页 For i = ii To numRows - 1 ' 跳过DataGridView的空行 If dataGridViewRows(i).IsNewRow Then Continue For ' 累计计算总计和税费 grand_total += CDbl(dataGridViewRows(i).Cells(10).Value) cgst += CDbl(dataGridViewRows(i).Cells(15).Value) sgst += CDbl(dataGridViewRows(i).Cells(17).Value) igst += CDbl(dataGridViewRows(i).Cells(13).Value) Dim formated_number As String = CDbl(dataGridViewRows(i).Cells(10).Value).ToString("F2") Dim formatednuber2 As String = formated_number.PadLeft(25 - formated_number.Length) Dim rate As String = CDbl(dataGridViewRows(i).Cells(7).Value).ToString("F2") Dim rate2 As String = rate.PadLeft(10 - rate.Length) e.Graphics.DrawString((i + 1).ToString(), dg_sales_entry.Font, Brushes.Black, l - 40, currentY) e.Graphics.DrawString(dataGridViewRows(i).Cells(4).Value.ToString(), dg_sales_entry.Font, Brushes.Black, l + 40, currentY) e.Graphics.DrawString(dataGridViewRows(i).Cells(5).Value.ToString(), dg_sales_entry.Font, Brushes.Black, right - 360, currentY) e.Graphics.DrawString(dataGridViewRows(i).Cells(12).Value.ToString(), dg_sales_entry.Font, Brushes.Black, right - 270, currentY) e.Graphics.DrawString(rate2, dg_sales_entry.Font, Brushes.Black, right - 200, currentY) e.Graphics.DrawString(dataGridViewRows(i).Cells(6).Value.ToString(), dg_sales_entry.Font, Brushes.Black, right - 120, currentY) e.Graphics.DrawString(formatednuber2, dg_sales_entry.Font, Brushes.Black, right - 60, currentY) currentY += dg_sales_entry.Rows(i).Height page_number += 1 ii += 1 ' 打印满10行且还有剩余数据时,触发分页 If page_number >= 10 And ii < numRows - 1 Then e.HasMorePages = True Exit For End If Next ' 只有最后一页打印总计和税费 If Not e.HasMorePages Then e.Graphics.DrawString(grand_total.ToString("F2"), dg_sales_entry.Font, Brushes.Red, right - 60, b - 180) e.Graphics.DrawString(sgst.ToString("F2"), dg_sales_entry.Font, Brushes.Black, right - 60, b - 220) e.Graphics.DrawString(cgst.ToString("F2"), dg_sales_entry.Font, Brushes.Black, right - 60, b - 200) e.Graphics.DrawString(igst.ToString("F2"), dg_sales_entry.Font, Brushes.Black, right - 60, b - 240) ' 重置状态变量,为下一次打印做准备 ii = 0 grand_total = 0 cgst = 0 sgst = 0 igst = 0 End If End Sub
关键修改说明
- 类级变量保存状态:将
ii、grand_total等变量移到类级别,确保分页时能延续上一页的打印位置和累计计算值。 - 修正分页标记逻辑:移除末尾强制设置
e.HasMorePages = False的代码,改为根据剩余数据动态设置,且只有打印满10行且还有数据时才触发分页。 - 资源自动释放:使用
Using语句包裹GDI+对象,避免内存泄漏。 - 总计打印优化:仅在最后一页打印累计的总计和税费,避免每页重复打印。
- 空行处理:跳过DataGridView的默认空行,防止打印无效数据。
内容的提问来源于stack exchange,提问作者Goventhran Palanisamy
相关产品推荐
相关产品推荐

