Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order of IsHandleCreated and InvokeRequired

I have the following code, and I've seen it written two different ways. I'm just curious which of the two ways is better practice:

if (this.IsDisposed) return;

if (this.IsHandleCreated)
{
    if (this.InvokeRequired)
    {
        this.Invoke(action);
    }
    else
    {
        action();
    }
}

log.Error("Control handle was not created, therefore associated action was not executed.");

vs.

if (this.InvokeRequired)
{
    this.Invoke(action);
}
else    
{
    if (this.IsDisposed) return;

    if (!this.IsHandleCreated)
    {
         log.Error("Control handle was not created, therefore associated action was not executed.");
         return;
    } 

    action();
}

I'm mostly concerned with issues stemming from actions that require a control have a handle, and those were it's not explicitly necessary. If I were to do something like this, it seems to solve my problems by ensuring that the control will have a handle before the action is executed. Thoughts?

if (control.InvokeRequired)
{
     control.Invoke(action);
}
else
{
    if (control.IsDisposed) return;

    if (!control.IsHandleCreated)
    {
        // Force a handle to be created to prevent any issues.
        log.Debug("Forcing a new handle to be created before invoking action.");
        var handle = control.Handle;
    }

    action();
}
like image 682
DTI-Matt Avatar asked Dec 05 '25 00:12

DTI-Matt


1 Answers

You should always check both IsDisposed and IsHandleCreated before checking InvokeRequired. This is a maddening scenario that I've spent many hours mastering.

Here are the states that a control can be in:

  • New: the control exists, but his handle hasn't been created. In this case, IsDisposed == false, IsHandleCreated == false, but InvokeRequired == false no matter what thread you use to call it. If you trust the results of InvokeRequired without testing (or knowing some other way) whether the handle has been created and whether the control has been disposed, you could accidentally cause the handle to get created associated with the wrong thread, and it would crash your app. (update) This state really only applies if the control is (or is a child of) a form whose handle hasn't been created yet.
  • Live: the control exists, its handle is created. This is the easy scenario, nothing strange about it.
  • Disposed: this is similar to the "New" state above, but IsDisposed == true. Again, InvokeRequired will lie to you and cause you misery.

The right way to do this would be:

if(control.IsDisposed || (!control.IsHandleCreated && !control.FindForm().IsHandleCreated))
{
    // some exceptional condition:
    // handle in whatever way is appropriate for your app
    return;
}

if(control.InvokeRequired)
{
    control.Invoke(action);
}
else
{
    action();
}

Additional Notes

In .Net 2.0 (and 3.x) this sucked much more. InvokeRequired will now walk the control hierarchy to determine if any ancestor control's handle has been created, and validated which thread it was created on. However, if the control is on a form that has never been shown, the same dangers apply. Previously (in 2.0 - 3.5), InvokeRequired didn't walk the control hierarchy, leading to more opportunity for calamity.

like image 61
FMM Avatar answered Dec 06 '25 15:12

FMM



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!