PrintQueueWatch .Net库打印多份时PrintJob.JobID重复问题咨询
解决Excel 2003多份打印触发多次
jobdeleted事件的问题 先跟你说,我之前也碰到过老版本Office打印监控的坑,尤其是Excel 2003这种古董级别的,它的打印行为和现在的Office完全不一样。结合你的环境(Windows XP、.NET 4.0、PrintQueueWatch库),咱们来拆解问题和解决方案:
问题根源
Excel 2003在打印多份文档时,底层会把每一份都作为独立的打印作业提交到系统打印队列,而不是像新版本Office那样合并成一个作业。这不是PrintQueueWatch库的问题,是老Office打印架构的限制——当年的打印系统对多份打印的处理就是拆分提交,所以你会看到3份打印生成3个JobID,每个都触发jobdeleted事件。
可行的解决方案
1. 通过作业元数据关联同批次打印任务
既然没办法让Excel只生成一个JobID,那咱们就主动识别哪些JobID属于同一次打印会话。可以通过以下几个字段来分组:
DocumentName:打印的文档名(Excel会保持一致)UserName:提交打印的用户名SubmittedTime:作业提交时间(多份打印的提交时间间隔极短,一般在1秒内)
我写了个简单的缓存逻辑,用来合并同批次的打印作业:
// 用来缓存同批次打印作业的辅助类 private class BatchPrintJob { public string DocName { get; set; } public string User { get; set; } public DateTime SubmitTime { get; set; } public int TotalCopies { get; set; } } private List<BatchPrintJob> _batchJobCache = new List<BatchPrintJob>(); // 时间阈值,根据实际打印速度调整,一般1秒足够 private readonly TimeSpan _batchThreshold = TimeSpan.FromSeconds(1); private void PrintQueue_JobDeleted(object sender, PrintJobEventArgs e) { var currentJob = e.PrintJob; lock (_batchJobCache) // 线程安全,因为事件可能在后台触发 { // 查找缓存中匹配的同批次作业 var matchedBatch = _batchJobCache.FirstOrDefault(b => b.DocName.Equals(currentJob.DocumentName, StringComparison.OrdinalIgnoreCase) && b.User.Equals(currentJob.UserName, StringComparison.OrdinalIgnoreCase) && currentJob.SubmittedTime - b.SubmitTime <= _batchThreshold); if (matchedBatch != null) { // 属于同批次,累加份数 matchedBatch.TotalCopies++; } else { // 新的打印批次,加入缓存 _batchJobCache.Add(new BatchPrintJob { DocName = currentJob.DocumentName, User = currentJob.UserName, SubmitTime = currentJob.SubmittedTime, TotalCopies = 1 }); // 5秒后清理过期缓存,避免内存占用 Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(_ => { lock (_batchJobCache) { _batchJobCache.RemoveAll(b => currentJob.SubmittedTime - b.SubmitTime > TimeSpan.FromSeconds(5)); } }); } } // 你可以在缓存清理时,对合并后的批次进行统一处理 // 比如记录一次打印任务,份数为TotalCopies }
2. 调整Excel打印方式(如果允许的话)
如果用户操作流程可以调整,让用户先把Excel工作表打印到文件(生成.prn文件),然后再打印这个文件。这样系统只会生成一个打印作业,自然就只有一个JobID,触发一次jobdeleted事件。不过这个方法依赖用户配合,可能不是所有场景都适用。
3. 忽略重复作业的临时处理
如果你的需求只是统计打印次数而不是每份的细节,可以在事件触发时,判断最近是否有相同文档名的作业被处理过,短时间内重复的就跳过。不过这个方法不如第一种精准,容易误判。
注意事项
- Windows XP和.NET 4.0本身也是老环境,要注意线程安全问题——PrintQueueWatch的事件是在后台线程触发的,操作缓存时一定要加锁。
- 时间阈值可以根据实际打印速度微调,如果你的打印机很慢,间隔可能会长一点,适当调大阈值即可。
内容的提问来源于stack exchange,提问作者vicangel
相关产品推荐
相关产品推荐

