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();
}
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:
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.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With