Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke or BeginInvoke cannot be called on a control until the window handle has been created

Tags:

c#

winforms

I get the following exception thrown:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

This is my code:

if (InvokeRequired)
{
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
}
else
    Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);

I found pages about this topic on this site but I don't know what is wrong.

like image 357
senzacionale Avatar asked Aug 24 '11 20:08

senzacionale


5 Answers

The difference between Invoke and BeginInvoke is that the former is synchronous (waits for completion) while the later is asynchronous (sort of fire-and-forget). However, both work by posting a message to the UI message loop which will cause the delegate to be executed when it gets to that message.

The InvokeRequired property determines whether you need to Invoke at all or if it is already on the correct thread, not whether you want synchronous or asynchronous calling. If InvokeRequired is false you are (in theory) already running on the UI thread and can simply perform synchronous actions directly (or still BeginInvoke if you need to fire them off asynchronously). This also means you can't use Invoke if InvokeRequired is false, because there's no way for the message loop on the current thread to continue. So that's one big problem with your code above, but not necessarily the error you're reporting. You can actually use BeginInvoke in either case, if you watch out for recursive invocation, and so on.

However, you can't use either one without a window handle. If the Form/Control has been instantiated but not initialized (ie. before it is first shown) it may not have a handle yet. And the handle gets cleared by Dispose(), such as after the Form is closed. In either case InvokeRequired will return false because it is not possible to invoke without a handle. You can check IsDisposed, and there is also a property IsHandleCreated which more specifically tests if the handle exists. Usually, if IsDisposed is true (or if IsHandleCreated is false) you want to punt into a special case such as simply dropping the action as not applicable.

So, the code you want is probably more like:

if (IsHandleCreated)
{
    // Always asynchronous, even on the UI thread already.  (Don't let it loop back here!)
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
    return; // Fired-off asynchronously; let the current thread continue.

    // WriteToForm will be called on the UI thread at some point in the near future.
}
else
{
    // Handle the error case, or do nothing.
}

Or maybe:

if (IsHandleCreated)
{
    // Always synchronous.  (But you must watch out for cross-threading deadlocks!)
    if (InvokeRequired)
        Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
    else
        WriteToForm(finished, numCount); // Call the method (or delegate) directly.

    // Execution continues from here only once WriteToForm has completed and returned.
}
else
{
    // Handle the error case, or do nothing.
}
like image 130
Rob Parker Avatar answered Oct 29 '22 19:10

Rob Parker


This will typically happen in multithreaded scenarios where some external source (maybe a NetworkStream) pushes data to a form before the form has properly initialized.

The message can also appear after a Form is disposed.

You can check IsHandleCreated to see if a form is already created, but you need to put everything in proper error handling as the Invoke statement can throw an exception if you try to update your form while your application is closing.

like image 23
Albin Sunnanbo Avatar answered Oct 29 '22 19:10

Albin Sunnanbo


here is my answer

Let's say you want to write"Hello World" to a text box. Then IF you use "Ishandlecreated" then your operation will not happen if handlers are not yet created. So You must force itself to CreateHandlers if not yet created.

Here is my code

if (!IsHandleCreated)
    this.CreateControl();

this.Invoke((MethodInvoker)delegate
{
  cmbEmail.Text = null;

});
like image 7
Real Programmer Avatar answered Oct 29 '22 19:10

Real Programmer


Assuming the form is not disposed but not yet fully initialized just put var X = this.Handle; before that if statement... by this the instance of the respective form is meant.

see http://msdn.microsoft.com/en-us/library/system.windows.forms.control.handle.aspx .

like image 3
Yahia Avatar answered Oct 29 '22 19:10

Yahia


If you're going to use a control from another thread before showing the control or doing other things with the control, consider forcing the creation of its handle within the constructor. This is done using the CreateHandle function. In a multi-threaded project, where the "controller" logic isn't in a WinForm, this function is instrumental for avoiding these kinds of errors.

like image 3
lmat - Reinstate Monica Avatar answered Oct 29 '22 19:10

lmat - Reinstate Monica