2010-07-25 71 views
1

我有UI WPF應用程序。BackgroundWorker問題

可能被一些人不得不爲什麼這個代碼不工作的任何想法?

案例1:

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += delegate 
{ 
    //some logic 
}; 

worker.RunWorkerAsync(); 

在這種情況下,我得到異常 調用線程,因爲不同的線程擁有它不能訪問該對象。 於是我改成了這樣:

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += delegate 
{ 
    this.Dispatcher.BeginInvoke(
    new Action(() => { //my code here }), null); 
}; 

這段代碼執行過程中UI漸凍後。就像是在同一個線程

案例2執行:

BackgroundWorker worker = new BackgroundWorker(); 
worker.RunWorkerAsync(new Action(() => 
{ 
//some code here 
})); 

在這種情況下,代碼中的行動不執行。

// ----------------------------------修訂--------- ----------------------------- //
謝謝傢伙是幫忙 爲什麼我的代碼不正確的是工作的原因如以下所說的。我確實在後臺線程中訪問了一些UI元素。現在我正在調用BackgroundWorker之前從UI元素中獲取所有值。我現在聲明新變量,爲它們分配來自所需UI元素的所有值,然後將這些變量傳遞給BackgroundWorker而不是UI元素(這是它最初的作用)。

+1

定義「不工作」。你在期待什麼?什麼沒有發生?任何錯誤?例外? – Oded 2010-07-25 06:49:17

+0

這個Dispatcher中的'this'是什麼。這是一個在UI線程上創建的UI元素嗎? – 2010-07-25 07:30:08

+0

我剛纔說了這個描述。 是的,它是UI WPF App – Juk 2010-07-25 07:53:54

回答

1

與第一個版本的問題是內部「一些邏輯」你可能訪問WPF對象 - 你不能做到這一點,WPF對象只能從創建它們的同一個線程訪問。

第二個版本的問題在於,您正在啓動一個後臺線程,要求主線程完成所有工作然後退出,因此您正在主線程上執行所有工作(即所有UI工作)和UI凍結,實質上這相當於根本不使用BackgroundWorker。

第三個版本,喬恩斯基特說,簡單不正確的使用和不應該工作像你認爲它是。

所以,你需要做什麼?

您需要在啓動後臺工作者之前從主線程中的UI中收集所有信息,只能使用簡單類型(字符串,int,double等)和線程安全類/結構體,您可以在由BackgroundWorker執行的代碼中不使用任何WPF類。

當您完成收集所有可以調用RunWorkerAsync的數據後,您在DoWork處理程序中無法從UI讀取數據 - 只能訪問您之前準備的數據,也無法寫入UI - 您有將其保存到其他位置(例如類成員),並在BackgroundWorker完成後將其複製到UI中。

在調用Freeze方法之後,「無法從另一個線程訪問WPF」規則的唯一例外是Freezable(以及所有繼承自Freezable的類),這使對象成爲只讀且線程安全的。

+0

謝謝Nir的非常詳細的解釋。現在我明白我的錯誤了。 – Juk 2010-07-26 11:41:32

1

第二個版本不會做你想要的,因爲參數RunWorkerAsync需要一個參數,它只是爲DoWorkEventArgs.Argument設置的值。這並不意味着要執行的動作 - 除非你提供一個事件處理程序,將值轉換爲Action並將其稱爲...

第一個版本應該可行 - 但根據Oded的評論,您還沒有給出任何指示你的意思是「不工作」......你也沒有指定兩個版本是失敗還是隻有一個。

0

另一件需要非常小心的事情是:如果您將DoWork設置爲匿名方法,請確保您未在​​調用方法中的對象上創建閉包。這些對象位於調用方法的線程上,如果方法觸及它們,這是一件不好的事情。

一個簡單的例子:

MyClass foo = new MyClass(); 
worker.DoWork += delegate 
{ 
    foo.MyProperty++; 
}; 

我一般使用匿名方法非常謹慎。如果你沒有故意使用它們,閉包會產生各種問題。如果你有意使用它們,很容易就會寫出一些微妙的代碼來修改一年的代碼。使用顯式參數編寫一個命名的方法可能需要更多的時間和代碼,但並沒有比記錄關閉操作更難。

我不使用匿名方法在所有BackgroundWorker。不僅有沒有真正考慮它的所有含義而依賴於閉包的風險,而且你也很可能編寫了不能被單元測試的代碼。

相關問題