I want to run an operation on a background thread. When it has completed I want to check for any errors that occurred and re-throw them on my original thread.
I am using a backgroundworker. Throwing an exception in the RunWorkerCompleted event handler results in an unhandled exception - this makes sense if the eventhandler is running on the background thread. If I had a winform control I could call Invoke or BeginInvoke but I do not have a winform control in this object, although it is a winform project.
How can I re-throw an exception that occurred in the backgroundworker?
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// I want to throw an exception here, without causing an unhandled exception and without being able to call Invoke or BeginInvoke on a WinForm control.
}
else if (e.Cancelled)
{
// Do something useful
}
else
{
if (e.Result != null)
{
// Do something with the result
}
}
}
I would have assumed that the RunWorkerCompleted event handler would be running on the original calling thread. Perhaps the backgroundworker is not what I need in this case.
BeginInvoke : This is a functionally similar to the PostMessage API function. It posts a message to the queue and returns immediately without waiting for the message to be processed. BeginInvoke returns an IAsyncResult , just like the BeginInvoke method on any delegate.
Invoke : Executes on the UI thread, but calling thread waits for completion before continuing. Control. BeginInvoke : Executes on the UI thread, and calling thread doesn't wait for completion.
The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the current control's underlying window handle does not exist yet. If no appropriate handle can be found, the Invoke method will throw an exception.
Invoke() makes sure that the invoked method will be invoked on the UI thread. This is useful when you want to make an UI adjustment in another thread (so, not the UI thread). InvokeRequired checks whether you need to use the Invoke() method.
It's not possible to inject code into another running thread. Not even the operating system can do this.
Control.BeginInvoke works by putting the delegate reference in a queue and then using PostMessage to post a user-message into the UI thread's message queue. The Application.Run message loop looks for this message and when it finds it pops the delegate off the queue and executes it.
The point is that there is no other way to do what you need without your main thread being coded to look for a some kind of signal (or message) from the other thread.
Added
You stated that this is a WinForm application but you do not have a Control to use BeginInvoke with.
Edit: I suggested a lazy-load without thinking it through. The Control might end up getting created on the wrong thread.
Pre-create a Control prior to Application.Run
that lives for the lifetime of the app. You can use this to BeginInvoke from.
Edit #3
So then I try this to make certain it works and of course it doesn't. You can't simply create a generic Control, it must have an HWND handle. Simple fix: create it like this:
invokerControl = new Control();
invokerControl.CreateControl();
That will allow you to BeginInvoke from it, even if there are no open Form objects to invoke from.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With