senzacionale
senzacionale

Reputation: 20906

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

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.

Upvotes: 38

Views: 86092

Answers (8)

Gourou Dsecours
Gourou Dsecours

Reputation: 27

What about this :

public static bool SafeInvoke( this Control control, MethodInvoker method )
{
    if( control != null && ! control.IsDisposed && control.IsHandleCreated && control.FindForm().IsHandleCreated )
    {
        if( control.InvokeRequired )
        {
            control.Invoke( method );
        }
        else
        {
            method();
        }
        return true;
    }
    return false;
}

Use it like that :

this.label.SafeInvoke(new MethodInvoker( () => { this.label.Text = yourText; }));

Upvotes: 2

amos godwin
amos godwin

Reputation: 956

Add this before you call your invoke method:

while (!this.IsHandleCreated) 
System.Threading.Thread.Sleep(100)  

This solution worked for me.

Upvotes: 6

Real Programmer
Real Programmer

Reputation: 337

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;

});

Upvotes: 8

Felice Pollano
Felice Pollano

Reputation: 33242

You are probably calling this in the constructor of the form, at that point the underlying system window handle does not exist yet.

Upvotes: 3

Rob Parker
Rob Parker

Reputation: 4196

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.
}

Upvotes: 73

lmat - Reinstate Monica
lmat - Reinstate Monica

Reputation: 7768

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.

Upvotes: 3

Albin Sunnanbo
Albin Sunnanbo

Reputation: 47038

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.

Upvotes: 10

Yahia
Yahia

Reputation: 70369

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 .

Upvotes: 5

Related Questions