I’m trying to create GUI program that generates HTML invoices, and sends them for printing.
I have this working. However, now I want to introduce threading.
I have a form with a BackgroundWorker. The Background worker runs this code:
#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();
}
Everything runs through fine. However, the WebBrowser object refuses to print. There are no errors (that are obvious), the program finishes off with nothing sent to the printer.
When I take away the threading, the program works again.
My knowledge of threading is weak, and I’m pretty much teaching myself – so presumably I’m misunderstanding how threading priority is set.
Here’s How it should work:
- User selects Invoice(s) on Main Form, chooses to print.
- Background thread goes away and prints them while user continues on the program.
Any ideas would be appreciated.
Main problem with your code is
WebBrowserwrong using.WebBrowsersupposed to be used for interactive web-browsing, during it user do some things in the internet. But in your case you are using WebBrowser just for the printing after downloading the html. This is wrong by two reasons:BackgroundWorkerclass supposed to be used forMuch more:
Your code will fail in the background thread, because WinForms control is a
user-interface object.Just for the record, WebBrowser.Print method invokes native windows API, so you have no chance that this will work in background. From the disassembly code:
So, my suggestion for your code is:
WebBrowserclass in the background. UseHttpWebRequestinstead for downloading the web content.PrintDocumentimplementation (example for it is here).Boolean Background, I think this can help you). As far as I know, even in 2010 this approach works well.PS: in the comments you’ve said that you may need the
PDFfrom your html. I did this by C# by two ways:This Add-in should be installed on the server, after that you can easily use MS Office classes for saving the output in the PDF format.
Some update here:
As we have an
async/awaitand TPL options for the time-consuming operations, I don’t recommend you to use theBackgroundWorkerclass anymore.