You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# PrintDocument用e.HasMorePages分页打印QRCode无限分页崩溃

问题根因

你的代码出现无限分页崩溃是3个核心逻辑错误导致的:

  1. 没有记录全局打印进度:PrintPage事件每次触发时,你都从头遍历所有DataRow、从i=0开始循环二维码生成逻辑,完全没有用到BeginPrint里初始化的currentItem变量记录上一次打印停在了哪个二维码。第一次进入PrintPage时i=0,i%5 ==0成立,直接设置e.HasMorePages = true返回;下一次PrintPage触发后又从头开始跑循环,再次遇到i=0触发分页返回,无限重复这个流程就会导致程序卡死崩溃。
  2. 分页计数维度错误:你用的i%5是单条DataRow内的二维码局部计数,不是所有待打印二维码的全局计数,跨数据行时计数会重置,根本无法准确统计单页打印的二维码数量。
  3. 重复冗余计算:每次触发PrintPage都遍历全表计算总二维码数,既浪费性能,也没有把总数值和分页判断逻辑关联起来。
    另外你的代码还存在GDI资源泄漏问题:生成的Bitmap二维码对象、Font对象用完没有释放,打印页数多了会占满内存加剧崩溃。
修复方案

核心思路是在全局维护打印进度状态,每次PrintPage只打印当前页最多5个二维码,打完后根据剩余待打印内容判断是否需要分页,不要每次从头遍历数据。

第一步:定义类级别的全局状态变量

// 记录当前已经打印到第几个二维码(全局索引)
private int currentPrintIndex = 0;
// 所有待打印二维码的内容列表(提前展平,避免遍历DataRow计数)
private List<string> qrToPrint = new List<string>();
// 单页最多打印二维码数量(按你实测的A4容量设为5)
private const int QrPerPage = 5;
// 单个二维码块高度(200px二维码 + 20px下方文本间距)
private const int QrBlockHeight = 220;

第二步:修改BeginPrint事件

在打印开始前一次性把所有要打印的二维码内容展平到列表,初始化打印进度,不要在PrintPage里重复计算总数:

private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
    currentPrintIndex = 0;
    qrToPrint.Clear();
    // 提前把所有需要打印的二维码按顺序存入列表
    foreach (DataRow dr in dt.Rows)
    {
        // 跳过二维码内容、数量为空的行
        if (dr[1] == DBNull.Value || string.IsNullOrWhiteSpace(dr[1].ToString())) continue;
        if (dr[4] == DBNull.Value || string.IsNullOrWhiteSpace(dr[4].ToString())) continue;

        string qrContent = dr[1].ToString();
        int qrCount = Convert.ToInt32(dr[4].ToString());
        // 按需要的数量把二维码内容加入打印列表
        for (int i = 0; i < qrCount; i++)
        {
            qrToPrint.Add(qrContent);
        }
    }
}

第三步:重写PrintPage事件逻辑

每次进入事件只处理当前页的内容,打满5个就标记分页返回,所有内容打完就结束打印:

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
    using (Font fontNormal = new Font("Arial", 12, FontStyle.Regular))
    {
        Brush textBrush = Brushes.Black;
        float left = e.MarginBounds.Left;
        float top = e.MarginBounds.Top;
        float currentY = top;
        int printedCount = 0;

        // 从上次打印结束的位置继续,不要从头开始
        while (currentPrintIndex < qrToPrint.Count)
        {
            // 当前页已经打满5个,标记还有下一页,退出当前页打印
            if (printedCount >= QrPerPage)
            {
                e.HasMorePages = true;
                return;
            }

            // 绘制二维码和下方文本,using自动释放Bitmap资源
            string content = qrToPrint[currentPrintIndex];
            using (Bitmap qrBmp = GenerateQRCODE(content))
            {
                e.Graphics.DrawImage(qrBmp, left, currentY, 200, 200);
            }
            e.Graphics.DrawString(content, fontNormal, textBrush, left + 40, currentY + 180);

            // 更新位置和计数
            currentY += QrBlockHeight;
            printedCount++;
            currentPrintIndex++;
        }

        // 所有二维码打印完成,没有后续页
        e.HasMorePages = false;
    }
}

说明

你项目中使用的PrintBar控件不影响上述分页逻辑,分页是PrintDocument组件的标准机制,和预览控件无关。如果实测单页能容纳的二维码数量和5有偏差,直接修改QrPerPage常量即可,调整QrBlockHeight可以适配不同的二维码、文本尺寸的间距。


内容的提问来源于stack exchange,提问作者Molnar Istvan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:06:27