Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke a method on the main thread without a WinForm control to call Invoke or BeginInvoke on

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.

like image 343
Peter Kelly Avatar asked Aug 16 '10 14:08

Peter Kelly


People also ask

What is BeginInvoke?

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.

What is the difference between Invoke and BeginInvoke method in C#?

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.

Why we use invoke in C#?

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.

What is invoke required?

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.


1 Answers

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.

like image 173
Tergiver Avatar answered Sep 22 '22 09:09

Tergiver