2012-03-18 117 views
5

我用一個BackgroundWorker和做到這一點:爲什麼我沒有拿到「跨線程操作無效」的錯誤

private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    this.Text = "RunWorkerAsync()"; 
    backgroundWorkerLoading.RunWorkerAsync(); 
} 
private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e) 
{ 
    UnsafeThreadMethod("hello"); 
    EvenUnsaferThreadMethod(); 
} 

而現在的兩種方法。

private void UnsafeThreadMethod(string text) 
{ 
    toolStripLabelRssFeedData.Text = text; 
} 

private void EvenUnsaferThreadMethod() 
{ 
    panelLoading.Visible = true; 
} 

我不明白爲什麼UnsafeThreadMethod不會拋出以下異常,但EvenUnsaferThreadMethod一樣。

跨線程操作無效:控制'panelLoading'從其創建的線程以外的線程訪問。

根據消息,這是因爲toolStripLabelRssFeedData是在同一個線程上創建的,但它不是。

我以爲我不能調用主線程創建的控件,必須使用ProgressChanged事件。這是怎麼回事?

我還有第二個問題。當我可以使用ProgressChanged時,這樣做的優點是什麼?我該怎麼辦?

private void EvenUnsaferThreadMethod() 
{ 
    if (panelLoading.InvokeRequired) 
    { 
     panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); })); 
    } 
    else 
    { 
     panelLoading.Visible = true; 
    } 
} 

回答

5

關於第一個問題:

  • 的跨線程的例外是故意拋出Debug模式。這意味着對大部分GUI控件內置的InvokeRequired進行(條件)代碼檢查。像小組一樣。

  • 顯然這個ToolstripLabel沒有做這個檢查。由於它不是來自控制,可能是因爲它超出了本安全網的範圍。

由於標準免責聲明「的任何實例成員不能保證線程安全的」適用於ToolstripLabel設置文本的時候,我只想與正常InvokeRequired邏輯去。

+1

我認爲這個答案解決了OP所問的問題,這就是爲什麼一個看起來不安全的呼叫並沒有拋出異常。這一切都圍繞着這樣的事實:ToolStripLabel不是從Control派生的,因此不檢查線程的安全性。它恰好適用,但正如其他人指出的那樣,你不能指望永遠保持真實。 – 2012-03-18 14:50:45

0

選擇的優點是,它工作 :)

所有UI元素在主UI線程創建的,什麼是從這個角度看問題,更重要的,是可以成爲只能在該線程中使用

這就是爲什麼你的第一情況下失敗,那就是你的情況下將工作的原因的原因。 Invoke()...會將所需的merhod調用重定向到主UI線程。

希望這會有所幫助。

+0

謝謝你的回答。你說'UnsafeThreadMethod'不應該工作,因爲UI的東西是在不同的線程,但它以某種方式,這是我不明白。另外,最後一個問題是如果最好使用Invoke的東西或者'ProgressChanged'和'RunWorkerCompleted'(因爲它們回到了正確的線程上,這會起作用)。 – pelz 2012-03-18 14:14:58

+0

第一個案件*有時*作品聽起來很奇怪。第二種情況如何:考慮到在你的方法中訪問UI元素,你必須*使用'Invoke'來將調用重定向到UI線程。它不能以其他方式工作。 – Tigran 2012-03-18 14:25:36

+0

不知何故,它會導致行爲不確定。它可以隨意修改,在服務包中修復。 – TomTom 2012-03-18 14:25:52

3

對於你的第一個問題,我不完全確定,但網上審查似乎表明,有時這不會引發異常,但它不會更新標籤。這是這種情況嗎?您的標籤是否隨着沒有例外而更新?

但是,我現在可以回答你第二個問題。 ProgressChanged事件的意思正是它聽起來像。它應該被調用來讓UI線程知道背景工作者的狀態,以便它可以適當地更新自己。原始調用線程(在這種情況下爲UI)是用於ProgressChanged的線程,因此當它更新時不需要調用Invoke。但是,這隻能用於顯示後臺工作人員的進度。

現在,如果它不是您嘗試傳遞給調用方法的更新,那麼我會建議將您的返回數據通過RunWorkerCompleted事件返回。這會將所有最終數據傳回原始(UI)線程,以便它可以更新UI而不需要任何Invoke

所以,是的,你打給Invoke的電話會起作用。然而,理解其他事件的作用可以幫助你理解爲什麼要用另一種方式。也許ProgressChanged事件適合更好?它也可以消除不必要的調用代碼。

更新到第一Q-

我仍然無法找到的工具條不需要的invoke什麼。事實上,我發現相反的使用谷歌搜索,如「toolstriplabel沒有交叉線程異常」或「toolstriplabel調用」等。但是,正如henk提到的,toolstriplabel沒有從控制繼承,以便可以解釋爲什麼不需要調用。不過,我的建議是假設它將像任何其他UI控件一樣工作,並確保它在UI線程上更新以確保安全。 不依賴怪癖。有備無患,你永遠不知道,如果這樣的事情可能會發生變化,特別是因爲它在邏輯上是一個UI項最..,

+0

謝謝你的回答。關於第一個問題:是的,它會更新標籤。你對我的第二個問題的回答解決了很多問題。我認爲在我的情況下'RunWorkerCompleted'就是要走的路。 – pelz 2012-03-18 14:27:30

+0

很高興幫助。我更新了我的答案,在進一步研究後給出了我對標籤的看法 – 2012-03-18 14:46:21

相關問題