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
相关产品推荐
相关产品推荐

