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

C#中PrintPreviewDialog预览正常,点击打印图标却输出空白页?

问题根源

你猜的完全正确——StringReader在预览时已经被读取到末尾,实际打印时没有内容可读,所以输出空白页。

预览窗口显示内容时,printDocument1_PrintPage事件会被触发,把myReader里的所有内容逐行读完;当你点击预览里的打印按钮时,myReader的指针已经停在文本末尾,再调用ReadLine()只会返回null,自然打印空白。

解决方法

核心思路是:每次启动打印任务(不管是预览还是实际打印),都重新生成打印文本并初始化StringReader。我们可以利用PrintDocument的BeginPrint事件——这个事件会在每次打印任务开始时触发,刚好用来重置打印内容。

步骤1:添加BeginPrint事件处理

在窗体类里添加printDocument1_BeginPrint方法,把生成打印文本和创建StringReader的逻辑移到这里:

private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
    string strText = "";
    string poBox = "PO BOX";
    string clientName = "CLIENT NAME";
    string breCount = "BRE COUNT";
    string fcCount = "FC COUNT";

    // 生成表头
    strText += poBox.PadRight(25, 'z');
    strText += clientName.PadRight(12, 'z');
    strText += breCount.PadRight(10, 'z');
    strText += fcCount.PadRight(10, 'z');
    strText += "\n";

    // 生成表格内容(增加空值判断避免报错)
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        poBox = row.Cells[0].Value?.ToString() ?? "";
        strText += poBox.PadRight(25, 'z');
        
        clientName = row.Cells[1].Value?.ToString() ?? "";
        strText += clientName.PadRight(12, 'z');
        
        breCount = row.Cells[2].Value?.ToString() ?? "";
        strText += breCount.PadRight(10, 'z');
        
        fcCount = row.Cells[3].Value?.ToString() ?? "";
        strText += fcCount.PadRight(10, 'z');
        strText += "\n";
    }

    // 重新初始化StringReader
    myReader = new StringReader(strText);
}

步骤2:修改按钮点击事件

移除btnPrint_Click里生成文本和创建Reader的代码,只保留预览窗口的配置逻辑:

private void btnPrint_Click(object sender, EventArgs e)
{
    printPreviewDialog1.Document = printDocument1;
    
    // 自定义预览窗口工具栏按钮的代码保留
    this.ToolStripButton = new ToolStripButton();
    this.ToolStripButton.Image = ((ToolStrip)(printPreviewDialog1.Controls[1])).ImageList.Images[0];
    this.ToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
    this.ToolStripButton.Click += new System.EventHandler(this.printPreview_PrintClick);
    ((ToolStrip)(printPreviewDialog1.Controls[1])).Items.RemoveAt(0);
    ((ToolStrip)(printPreviewDialog1.Controls[1])).Items.Insert(0, ToolStripButton);

    // 直接显示预览窗口,打印文本交给BeginPrint生成
    printPreviewDialog1.ShowDialog();
}

步骤3:绑定BeginPrint事件

在窗体的构造函数或者设计器里,把printDocument1的BeginPrint事件绑定到我们刚写的方法:

public frmView()
{
    InitializeComponent();
    printDocument1.BeginPrint += printDocument1_BeginPrint;
}
原理说明
  • 预览窗口启动时,会触发BeginPrint,生成新的StringReader,保证预览内容完整;
  • 点击预览里的打印按钮时,printDocument1.Print()会再次触发BeginPrint,重新生成StringReader,此时打印的内容是从头开始读取的完整文本;
  • 增加空值判断(row.Cells[0].Value?.ToString() ?? "")可以避免DataGridView单元格为空时抛出空引用异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:59:51