在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke

sen*_*ale 21 c# winforms

我抛出以下异常:

在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke.

这是我的代码:

if (InvokeRequired)
{
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
}
else
    Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
Run Code Online (Sandbox Code Playgroud)

我在这个网站上找到了关于这个主题的网页,但我不知道出了什么问题.

Rob*_*ker 54

Invoke和BeginInvoke之间的区别在于前者是同步的(等待完成),而后者是异步的(类似于"忘掉").但是,两者都通过向UI消息循环发布消息来工作,这将导致委托在到达该消息时执行.

InvokeRequired属性确定您是否需要完全调用或者是否已经在正确的线程上,而不是您是否需要同步或异步调用.如果InvokeRequired为false,您(理论上)已经在UI线程上运行,并且可以直接执行同步操作(或者如果需要异步触发它们,则仍然是BeginInvoke).这也意味着如果InvokeRequired为false,则无法使用Invoke,因为当前线程上的消息循环无法继续.这是您上面的代码的一个大问题,但不一定是您报告的错误.在任何一种情况下,如果你注意递归调用,你实际上可以使用BeginInvoke,依此类推.

但是,如果没有窗口句柄,则不能使用任何一个.如果表单/控件已经实例化但未初始化(即,在它首次显示之前),它可能还没有句柄.并且Dispose()会清除句柄,例如在Form关闭后.在任何一种情况下,InvokeRequired都将返回false,因为没有句柄就无法调用.您可以检查IsDisposed,并且还有一个属性IsHandleCreated,它更具体地测试句柄是否存在.通常,如果IsDisposed为真(或者如果IsHandleCreated为false),您想要进入一个特殊情况,例如简单地将操作丢弃为不适用.

所以,你想要的代码可能更像是:

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.
}
Run Code Online (Sandbox Code Playgroud)

或者可能:

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.
}
Run Code Online (Sandbox Code Playgroud)


Alb*_*nbo 8

这通常发生在多线程场景中,其中一些外部源(可能是NetworkStream)在表单正确初始化之前将数据推送到表单.

在处理表单后,也可以显示该消息.

您可以检查IsHandleCreated是否已创建表单,但是您需要将所有内容放入正确的错误处理中,因为Invoke如果您在应用程序关闭时尝试更新表单,则语句可能会引发异常.


amo*_*win 6

在调用调用方法之前添加以下内容:

while (!this.IsHandleCreated) 
System.Threading.Thread.Sleep(100)  
Run Code Online (Sandbox Code Playgroud)

这个解决方案对我有用。

  • 这将有助于即将初始化的表单/控件。如果表格已经处理完毕,那么添加睡眠只会推迟不可避免的事情。 (2认同)

Rea*_*mer 5

这是我的答案

假设你想在文本框中写"Hello World".然后,如果您使用"Ishandlecreated",那么如果尚未创建处理程序,则不会执行您的操作.因此,如果尚未创建,则必须强制自己使用CreateHandlers.

这是我的代码

if (!IsHandleCreated)
    this.CreateControl();

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

});
Run Code Online (Sandbox Code Playgroud)