Call a method in the main thread without a WinForm control to invoke Invoke or BeginInvoke on

I want to start an operation in a background thread. When it finishes, I want to check if any errors have occurred and re-throw them into the original stream.

I use a flashlight. Throwing an exception from the RunWorkerCompleted event handler results in an unhandled exception - this makes sense if the event handler is running in 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 this is a winform project.

How can I re-execute an exception that occurred in the background?

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 suggest that the RunWorkerCompleted event handler would run on the original call flow. Perhaps the magician is not the one I need in this case.

+4
source share
6 answers

Unable to enter code into another stream. Even the operating system cannot do this.

Control.BeginInvoke works by queuing a delegate link and then using PostMessage to send the user message to the message queue of the UI thread. The Application.Run message loop searches for this message, and when it finds it, it issues the delegate from the queue and executes it.

The fact is that there is no other way to do what you need if your main stream is not encoded to look for some signal (or message) from another stream.

Added

You stated that this is a WinForm application, but you do not have a control to use BeginInvoke with.

Edit: I suggested lazy loading without thinking about it. The control may end up creating in the wrong thread .

Pre-create the control before Application.Run , which lives throughout the life of the application. You can use this for BeginInvoke from.

Edit # 3

So, I'm trying to do this to make sure that it works, and of course not. You cannot just create a common control, it must have an HWND handle. Simple fix: create it like this:

 invokerControl = new Control(); invokerControl.CreateControl(); 

This will allow you to BeginInvoke from it, even if there are no open Form objects to call from.

+7
source

You can check from the other side. I mean - the place timer (which will work in the same main thread as the form) in your form, and once per second - check the Exceptions field in your form (using lock ()), as well as some object field , to find that this operation is completed, And then from bgw_RunWorkerCompleted wrap the code with try ... catch, and on catch (again with lock ()) set the Exception field of the form to an exception. But why not use Invoke or BeginInvoke?

+1
source

If you did not create a BGW instance in the user interface thread, its RunWorkerCompleted event will be fired on an arbitrary threadpool thread. Any exception that you throw on this thread is incompatible and will terminate your application with the last failure through AppDomain.UnhandledException.

In this case, BGW is simply of little use. It is nice to guarantee that its events will be executed in the user interface thread. You can also use MethodInvoker.BeginInvoke (). You will need to think about it a bit and decide what exactly you are going to do when some part of the code is disabled on some workflow, does not do its job. Dealing with such a failure is usually impossible and allows the program to crash and burn - this is the right thing.

If you want some way to notify the user and try to make the program stumble, then you really need to create a BGW instance in the user interface thread. And use, say, MessageBox.Show () in the RunWorkerCompleted event handler. Remember to restore the state of your program when you do this, you will almost certainly need a catch clause in DoWork () to clear the fragments.

+1
source

Do not throw an exception.

Raise an event in the background worker to which your main application thread joins, and then handle the error there - if necessary, throwing an exception if necessary.

0
source

Just handle the RunWorkerCompleted event. This event is synchronized for you.

  BackgroundWorker bgw; private void button1_Click(object sender, EventArgs e) { bgw = new BackgroundWorker(); bgw.DoWork +=new DoWorkEventHandler(bgw_DoWork); bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted); bgw.RunWorkerAsync(bgw); } void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) textBox1.Text = e.Error.Message; } void bgw_DoWork(object sender, DoWorkEventArgs e) { throw new NotImplementedException(); } 
0
source

If by chance you use 4.0, you can switch to using a task instead, which will do what you want. See an example

0
source

All Articles