2012-11-06 50 views
1

鑑於使用2種表單時是否需要兩次單獨的InvokeRequired檢查?

Action closeLoadingAction = new Action(() => 
{ 
    loadingForm.Close(); 
    #region - may need to put into second Action 
    panelOnMainForm.Controls.AddRange(physdocControls.ToList<Control>().ToArray()); 
    if (Handle != IntPtr.Zero) 
    User32DLL.SetForegroundWindow(this.Handle);//Handle is a property of the mainForm. 
    #endregion 
}); 

有時我得到把手不創建的異常,即使我檢查所需的調用。

if(loadingForm.InvokeRequired) 
    loadingForm.Invoke(closeLoadingAction); 
else 
    closeLoadingAction(); 

加載表單與主窗體在相同的線程上運行。您在上面看到的代碼運行在單獨的線程中。我懷疑我需要另一個檢查來調用主窗體。我需要再次檢查還是我已經安全?

+0

'Handle'從哪裏來,這是在控制中運行嗎?控件是否已創建(有句柄可用)?還有一種方便的擴展方法可以減少表單控件上的InvokeRequired檢查冗餘,但這是一個不同的故事。 –

+0

@QuintinRobinson - 已更新的問題。詳細的事情會很好......我在我的代碼中使用了很多次。 –

+1

WRT的擴展方法:看看這個答案http://stackoverflow.com/a/12179408/12707如果你是如此的傾向,你可以改變簽名爲'Action'而不是'MethodInvoker',但應該按原樣工作。 –

回答

2

你看到上面的代碼在一個單獨的線程

使用InvokeRequired這樣運行時,你知道這些代碼在另一個線程上運行是一個壞的反模式。你可以用它做更多有用的事情。像:

if (!loadingForm.InvokeRequired) { 
    throw new InvalidOperationException("Threading race detected"); 
} 
loadingForm.Invoke(closeLoadingAction); 

或者,如果你的意思是啓動加載線程加載窗體的Load事件被炒了魷魚更實用的一個:

while (!loadingForm.InvokeRequired) Thread.Sleep(50); 
loadingForm.Invoke(closeLoadingAction); 

或者只是做正確的方式有如下形式的Load事件啓動線程。

1

如果在您嘗試Invoke委託之前表單未顯示或已關閉,您應該只獲取那些「未創建句柄」異常。沒有足夠的代碼來確定是否是這種情況,所以如果我在你的鞋子裏,我會試着確定是否在方法被調用之前調用加載表單(因爲這是調用者)。

因爲兩個表單都在同一個線程上,所以只需檢查加載表單的InvokeRequired屬性即可安全。儘管一般情況下,如果您要在主窗體上操作,您應該檢查該窗體的InvokeRequired屬性。同樣,如果您要在裝貨單上操作(例如上面的電話號碼Close),您應該檢查裝貨單的InvokeRequired財產。上面你改變panelOnMainForm,所以我會檢查這是完全安全的,但我不認爲這是必要的。

+0

錯誤必須來自某件事。我不關閉加載表單。如果加載的MainForm和加載表單沒有句柄會怎麼樣?這不是一個問題嗎? –

+0

加載表單在它尚未顯示時(僅通過「Show」或「ShowDialog」)或已經關閉(通過「Close」或通過其GUI)時,不會顯示句柄_only_。我同意@MrBlue,這是一個種族,但沒有足夠的代碼讓我們看看它是如何發生的。 –

1

聽起來像是爲loadingForm創建的手柄和loadingForm.Close()的呼叫之間的競賽。

解決此問題的一個方法是在loadingForm.HandleCreated事件觸發時啓動線程,該線程具有代碼.Invoke/.Close

private void loadingForm_HandleCreated(object sender, EventArgs e) 
{ 
    var t = new Thread(DoLoadingStuff); 
    t.Start(); 
} 

private void DoLoadingStuff() 
{ 
    // ... 

    if(loadingForm.InvokeRequired) 
     loadingForm.Invoke(closeLoadingAction); 
    else 
     closeLoadingAction(); 
} 
相關問題