I have a need for users to be able to scan a series of items and for each item print off x number of labels. I am currently trying to use a background worker to accomplish this but I have run into a problem where they are scanning items so fast and there are so many labels to print for each item the background worker chokes. This is how I am generating the background worker thread for each scan because contention was occurring when there was a large number of labels be printed.
private void RunPrintWorker()
{
if (printWorker.IsBusy)
{
printWorker = new BackgroundWorker();
printWorker.DoWork += new DoWorkEventHandler(printWorker_DoWork);
printWorker.RunWorkerAsync();
}
else
printWorker.RunWorkerAsync();
}
I don’t get any exceptions from the background worker it just seems to not be creating threads fast enough. I am newer to using multiple threads so can anyone point me in the direction of what I am doing wrong?
Thanks.
EDIT: Thanks everyone for the suggestions and reading material this should really help. The order the labels are being printed doesn’t really matter since they are scanning pretty fast and the labels are only being printed to one printer too. I will mark an answer after I get the implementation up and running.
EDIT: Austin, below is how I have my printing method setup. Before I was just calling LabelPrinter.PrintLabels in my RunPrintWorker method. Now that I am redoing this I can’t figure out what to pass into the SizeQueue method. Should I be passing the newly created print document into it?
public class LabelPrinter
{
private int CurrentCount = 0;
private List<int> _selectedRows = new List<int>();
public List<int> SelectedRows
{
get { return _selectedRows; }
set { _selectedRows = value; }
}
private string _selectedTemplate;
public string SelectedTemplate
{
get { return _selectedTemplate; }
set { _selectedTemplate = value; }
}
private string _templateDirectory = string.Empty;
public string TemplateDirectory
{
get { return _templateDirectory; }
set { _templateDirectory = value; }
}
public void PrintLabels(PrintDocument printDoc, PageSettings pgSettings, PrinterSettings printerSettings, List<int> selectedRows, string selectedTemplate, string templateDir)
{
this._selectedRows = selectedRows;
this._selectedTemplate = selectedTemplate;
this._templateDirectory = templateDir;
printDoc.DefaultPageSettings = pgSettings;
printDoc.PrinterSettings = printerSettings;
printDoc.PrinterSettings.MaximumPage = selectedRows.Count();
printDoc.DefaultPageSettings.PrinterSettings.ToPage = selectedRows.Count();
printDoc.PrinterSettings.FromPage = 1;
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
printDoc.Print();
}
private void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
CurrentCount = DrawLabel.DrawLabelsForPrinting(e, SelectedTemplate, SelectedRows, CurrentCount, TemplateDirectory);
}
}
Try adding the items to a queue (for example,
Queue<Item>) and have the BackgroundWorker process the queue.EDIT: Adding some simple, untested code that may work for you. I would encapsulate the print queue with its processor and just send it jobs.
SizeQueue implementation
EDIT 2: Addressing the updated code in the question
First, I would define a
PrintJobclass that contains the number of copies to print and either the complete label text or enough data to derive it (like IDs for a DB query). This would lead you to replaceSizeQueue<string>in my code above toSizeQueue<PrintJob>as well asAddPrintItem(string item)toAddPrintJob(PrintJob job).Second, I would keep your LabelPrinter code separated (perhaps create that IPrinter interface) and pass that into the constructor of my SimpleLabelPrinter (which may not be the best name at this point but I’ll let you handle that).
Next, create your LabelPrinter and SimpleLabelPrinter (say
printer1for this example) wherever it’s appropriate for your app (in your apps Closing or “cleanup” method, be sure to set KeepProcessing to false so its thread ends).Now when you scan an item you send it to the SimpleLabelPrinter as: