I have a SafeInvoke Control extension method similar to the one Greg D discusses here (minus the IsHandleCreated check).
I am calling it from a System.Windows.Forms.Form as follows:
public void Show(string text) {
label.SafeInvoke(()=>label.Text = text);
this.Show();
this.Refresh();
}
Sometimes (this call can come from a variety of threads) this results in the following error:
System.InvalidOperationExceptionoccurred
Message= “Invoke or BeginInvoke cannot be called on a control until the window handle has been created.”
Source= “System.Windows.Forms”StackTrace: at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) at System.Windows.Forms.Control.Invoke(Delegate method) at DriverInterface2.UI.WinForms.Dialogs.FormExtensions.SafeInvoke[T](T control, Action`1 action) in C:\code\DriverInterface2\DriverInterface2.UI.WinForms\Dialogs\FormExtensions.cs:line 16
What is going on and how do I fix it? I know as much as it is not a problem of form creation, since sometimes it will work once and fail the next time so what could the problem be?
PS. I really really am awful at WinForms, does anyone know a good series of articles that explains the whole model and how to work with it?
It’s possible that you’re creating your controls on the wrong thread. Consider the following documentation from MSDN:
Let’s see what this means for you. (This would be easier to reason about if we saw your implementation of SafeInvoke also)
Assuming your implementation is identical to the referenced one with the exception of the check against IsHandleCreated, let’s follow the logic:
Consider the case where we’re calling
SafeInvokefrom the non-gui thread for a control whose handle has not been created.uiElementis not null, so we checkuiElement.InvokeRequired. Per the MSDN docs (bolded)InvokeRequiredwill returnfalsebecause, even though it was created on a different thread, the handle hasn’t been created! This sends us to theelsecondition where we checkIsDisposedor immediately proceed to call the submitted action… from the background thread!At this point, all bets are off re: that control because its handle has been created on a thread that doesn’t have a message pump for it, as mentioned in the second paragraph. Perhaps this is the case you’re encountering?