2011-08-24 65 views
15

不能在一个控件调用我得到下面的异常抛出:调用或BeginInvoke可直到窗口句柄已创建

调用或BeginInvoke不能上一个控制,直到窗口句柄已创建调用。

这是我的代码:

if (InvokeRequired) 
{ 
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
} 
else 
    Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 

,我发现关于这个网站主题相关的网页,但我不知道什么是错。

+1

不知道更多关于这个问题,它听起来就像你调用一个事件完全创建表单前/初始化,或在某些时候另一个线程它不该”不要。 –

+1

如果运行(System.Timers或的System.Threading)任何计时器,检查它们是否正在导致这个代码尚未完全构造或设置在表格上运行。 –

+0

这段代码在哪里,什么方法或事件处理程序? – Kev

回答

47

Invoke和BeginInvoke之间的区别在于前者是同步的(等待完成),而后者是异步的(有点让人失望)。但是,两者都通过向UI消息循环发布消息来工作,这将导致在获取该消息时执行委托。

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

但是,您不能使用任何一个没有窗口句柄。如果Form/Control已经实例化但未初始化(即在它首次显示之前),它可能还没有处理。并且句柄被Dispose()清除,例如在Form关闭之后。无论哪种情况,InvokeRequired都会返回false,因为不可能在没有句柄的情况下调用。您可以检查IsDisposed,并且还有一个属性IsHandleCreated,它更具体地测试句柄是否存在。通常,如果IsDisposed为true(或者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. 
} 

或许:

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

thx回答。 – senzacionale

+0

这也是得心应手对于调用主UI线程上的方法异步任务,但表单配置的调用被调用之前。 –

7

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

消息也可以在表单处理后出现。

您可以检查IsHandleCreated,看看是否已经创建了一个形式,但是你需要把正确的错误处理为Invoke声明一切,如果你尝试在你的应用程序被关闭,以更新的形式可以抛出异常。

2

如果你打算从另一个线程使用控制显示控制或做之前其他与控件的事情,考虑强制在构造函数中创建它的句柄。这是通过使用CreateHandle函数完成的。在多线程项目中,“控制器”逻辑不在WinForm中,此功能有助于避免这些类型的错误。

1

你可能会在形式的构造函数中调用这个,在这一点上的底层系统窗口句柄尚不存在。

5

这里是我的答案

比方说,你想要的“Hello World”写入一个文本框。 这时如果使用“Ishandlecreated”,那么就不会,如果尚未创建的处理程序发生在您的操作。所以你必须强制自己创建处理程序,如果还没有创建。

这里是我的代码

if (!IsHandleCreated) 
    this.CreateControl(); 

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

}); 
相关问题