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; 

}); 
相關問題