2009-09-28 56 views
1

更新:這裏是MSDN文章How to: Make Thread-Safe Calls to Windows Forms Controls。它指出:'跨線程操作無效'不會終止WinForms應用程序(它應該)

.NET框架幫助您檢測 當您訪問在不是線程安全的方式,你的控制 。 當你運行你的應用程序 在調試器,以及比創建一個控制 試圖調用該控件的一個線程其他 ,該 調試器引發 出現InvalidOperationException與 消息,「控制控制名稱 從訪問一個線程,而不是它創建的 線程。「

此異常期間 調試可靠和發生,在某些情況下 ,在運行時。

我以前的經歷是在運行時拋出異常。

感謝斯彭斯爲我指出了正確的方向。


我在WinForms應用程序一個很常見的錯誤:後臺線程訪問UI控件,而不是直接使用Control.BeginInvoke()。

我的問題是:我看到InvalidOperationException「跨線程操作無效:控制'uxCheckStatus'從一個線程以外的線程訪問它創建。」在後臺線程的調試器中,但是它在WinForms內部的某個地方被吞噬了。

我希望它殺死後臺線程和整個應用程序。

此外,觸發它的代碼uxCheckStatus.Text = "success";有時會在拋出異常期間/之後執行,即標籤文本讀取「成功」!我基本上失去了。任何人遇到這種行爲?

我使用1個按鈕在全新的WinForms解決方案上重現它,它們都使用ThreadPool和Thread for evil background線程。

如果我在後臺線程上拋出一個新的InvalidOperationException(),它會殺死應用程序。所以我唯一的猜測是WinForms在某處處理了這個特定的異常,但是我無法在網絡上找到這種行爲的參考。

我運行.NET 3.5,VS 2008

回答

3

這是設計。這是編碼錯誤,而不是運行時錯誤。 Winforms的開發人員決定從.Net 2開始,他們將實現代碼來檢查跨線程代碼,然後觸發MDA。但MDA並不是一個例外,它是對糟糕設計的代碼的檢查。

此外,當您的代碼處於發佈模式時,MDA不會觸發,它會每隔一段時間都會隨機失敗,MDA將在測試中幫助您,而不是在發佈期間。

我假設你正在重寫寫的不好的應用程序調用到線程和你所希望看到的異常會趕上你,我有一個建議:

更新您的事件處理程序的GUI東西看起來像這樣:

public void button_clicked_handler(object sender, EventArgs e) 
{ 
    if(this.InvokeRequired) 
{ 
    this.Invoke(delegateToThisMethod) 
} 
else 
{ 
    //perform method 
} 

這種模式將捕獲所有的方法,並使其交叉線程操作無縫。如果線程直接訪問代碼,這有點困難。你可以通過重命名一個控件來解決這個問題,然後創建一個屬性給控件,然後你可以在其中應用調用模式。我不得不這樣做,以解決一些非常時髦的跨線程的東西。

祝你好運;)

編輯: 只是想澄清,檢查當前線程的同步上下文和贏窗體線程是一個昂貴的操作。因此,他們實現MDA的原因是,您可以在調試中找到它,但是在每次訪問EVERY屬性或Windows窗體控件的方法時,您的發佈模式代碼都不會變慢。

+0

'MDA'是什麼?你有沒有提及'按設計'?讓我重複自己:我知道我應該使用'Control.BeginInvoke'。我認爲,當我忘記使用它時,應用程序應該'快速失敗',而不是吞下異常。 – 2009-09-28 21:32:57

+0

好的,在您提到調試模式後,我在MSDN上找到了它的參考,謝謝。 – 2009-09-28 21:52:51

+0

我知道它被埋在MSDN的某處。做好把信息放入問題中,很多人沒有意識到SO被設計成有用答案的存儲庫,像這樣的維護使得這個網站變得非常棒。祝你好運,你的調試,沒有像讀別人的代碼:) – Spence 2009-09-29 00:39:15

0

我不知道任何特定的文檔如何/爲什麼的WinForms處理此異常。但是,如果要在這種情況發生時正常關閉應用程序,請考慮global exception handler

+0

Application.ThreadException不被調用。 AppDomain.CurrentDomain.UnhandledException是,理論上我可以關閉它的應用程序。 – 2009-09-28 21:35:29