Reputation: 4257
I have a winforms application that was originally designed to be have different sequential functions triggered manually with buttons (4 buttons without corresponding backgroundworkers,4 buttons with corresponding backgroundworkers, 8 buttons total). Each button does some quick set up synchronously and then fires off a background worker to do the work asynchronously. This can be heavy work.
A decision was made to have an "express" option that does all the work of the 4 buttons with default options. Unfortunately I didn't design this as modular as I should have.
What I have done is have the ExpressButton call a 5th background worker, which in turn calls InvokeOnClick on each button in sequential order. Luckily the 4 non asynchronous buttons clicks get called first. I am using an AutoResetEvent to block the 5th backgroundworker while each sequential button is clicked.
Here is some pseudo code, buttons 1-4 don't call background workers, buttons 5-8 call backgroundworkers and _resetevent = new AutoResetEvent(false) in the global variables:
private void backgroundWorker5_DoWork(object sender, DoWorkEventArgs e)
{
ControlEventArgs automationcheck = new ControlEventArgs(expressButton);
InvokeOnClick(button1, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button2, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button3, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button4, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button5, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button6, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button7, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button8, automationcheck);
_resetevent.WaitOne();
_statusBox.AppendText("Finished" + Environment.NewLine);
}
So here is the strange thing. In the UI I have 2 textboxes where users enter information.
In backgroundworker1 (corresponding above to button5), I can access the .Text property of the first TextBox. However in backgroundworker2 (corresponding to button6), I cannot access the .Text property of the other TextBox. I can access it in the button6 click event all the way up until I call RunWorkerAsync(). As soon as I'm in the backgroundworker2 trying to access the TextBox.Text freezes the program up. No exception, it just stops.
Here is my theory : backgroundworker1 is called/run with no parameters from button5 click event backgroundworker2 is called/run with parameters from button6 click event By passing an objectlist in RunWorkAsync(params[]) am I causing it to NOT pass some context of the original form control? The funny thing here is that there is another textbox on the main form called statusBox that I can still access in backgroundworker2, in fact that's what I've been using for debugging purposes.
So to recap.
Button 9
Backgroundworker 5
Button 1
Button 2
Button 3
Button 4
Button 5
Backgroundworker 1
Can access TextBox.Text here
Button 6
Backgroundworker 2
Can't access TextBox.Text here
Button 7
Backgroundworker 3
unsure
Button 8
Backgroundworker 4
unsure
Worst case scenario :
Since button6 still has access to the textbox, I can grab the text out and pass it in the params list for runworkerasync. However I'd still like to know why 1 backgroundworker can see a textbox on the mainform and another can't.
Upvotes: 0
Views: 697
Reputation: 15151
Do as Austin said and Invoke() all the calls.
You're hitting this exception (i don't care if it's consistent) just randomly, any call to UI from a worker thread may lead to an exception as only the main thread must access the UI.
My bet is when you access the .Text property for the first time the control itself does not need to redraw, but the second time it needs, so you will end with a cross-threading exception.
Upvotes: 2