4

我正在尝试创建生成 HTML 发票并将其发送打印的 GUI 程序。
我有这个工作。但是,现在我想介绍线程。

我有一个带有BackgroundWorker. 后台工作人员运行以下代码:

#region BackGroundWorker   
private void bg_htmlGeneration_DoWork(object sender, DoWorkEventArgs e)
{
   //SOME MORE CODE..

   foreach (XElement ele in Lib.GetInvoiceElement(inv, ico.Supplier))
   {
      PrintDocument(Lib.CreateHTMLFile());
   }
}
#endregion  


public void PrintDocument(string fileName)
{
    var th = new Thread(() =>
    {
        WebBrowser webBrowserForPrinting = new WebBrowser();
        webBrowserForPrinting.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(PrintDocumentHandler);
        webBrowserForPrinting.Url = new Uri(fileName);
        Application.Run();
    });
    th.SetApartmentState(ApartmentState.STA);
    th.Start();
}

public void PrintDocumentHandler(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    ((WebBrowser)sender).Print();
    ((WebBrowser)sender).Dispose();
    Application.ExitThread();
}

一切顺利。但是,该WebBrowser对象拒绝打印。没有错误(很明显),程序结束时没有任何内容发送到打印机。
当我拿走线程时,程序再次运行。

我对线程的了解很薄弱,而且我几乎是在自学——所以大概我误解了线程优先级是如何设置的。

这是它应该如何工作的:

  1. 用户在主窗体上选择发票,选择打印。
  2. 当用户继续使用程序时,后台线程会消失并打印它们。

任何想法,将不胜感激。

4

1 回答 1

3

您的代码的主要问题是WebBrowser使用错误。

WebBrowser应该用于交互式网络浏览,在此期间用户在互联网上做一些事情。但在您的情况下,您使用 WebBrowser 只是在下载 html 后进行打印。这是错误的,原因有两个:

  1. 您的代码创建了整个 Windows 窗体控件,甚至没有使用它的一半功能。
  2. 您的代码尝试在后台线程中使用 WinForms 控件,这会导致意外行为。

BackgroundWorker应该用于的类

在后台执行耗时的操作(如下载和数据库事务)。

多得多:

您必须小心不要在事件处理程序中操纵任何用户界面对象。DoWork相反,通过ProgressChangedRunWorkerCompleted事件与用户界面进行通信。

您的代码将在后台线程中失败,因为 WinForms 控件是一个user-interface object.

仅作记录,WebBrowser.Print方法调用本机 Windows API,因此您不可能在后台运行。从反汇编代码:

this.AxIWebBrowser2.ExecWB(NativeMethods.OLECMDID.OLECMDID_PRINT, 
  NativeMethods.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, 
  ref obj, 
  IntPtr.Zero);

因此,我对您的代码的建议是:

  1. WebBrowser在后台删除类的使用。HttpWebRequest改为用于下载 Web 内容。
  2. 选择其他方式打印下载的内容。选项是:

PS:在您所说的评论中,您可能需要PDF来自您的html。我通过 C# 通过两种方式做到了这一点:


这里有一些更新:

由于我们有一个async/awaitTPL选项用于耗时的操作,我不建议您再使用BackgroundWorker该类。

于 2012-11-02T10:45:08.633 回答