2012-07-24 45 views
2

我發現對於我目前的情況看起來像一個非常簡單的解決方案。使用匿名方法從單獨的線程更新GUI的說明

我目前的情況是,我想對新線程做一些I/O操作,這樣我就不會陷入我的GUI線程。我有一個函數,作爲我的表單的一員,已經完成了這些I/O操作,但是在GUI線程上運行它確實使應用程序很難使用。所以我的計劃是在一個新的線程中運行這個函數。所以,我在表單中創建了一個Thread變量,並試圖讓它使用該函數作爲ThreadStart參數。但它似乎並不喜歡它。

我發現一個優雅的外觀解決方案,作爲對另一個線程的響應,here

///...blah blah updating files 
string newText = "abc"; // running on worker thread 
this.Invoke((MethodInvoker)delegate { 
    someLabel.Text = newText; // runs on UI thread 
}); 
///...blah blah more updating files 

從該響應的外觀上來看,我可以在一個新的線程中運行該功能,然後可以使用匿名函數來更新自己的狀態,當線程完成計算。儘管如此,我還不足以填補答覆的空白。

所有我似乎讀到的線程說,我的ThreadStart函數需要是一個新類中的靜態方法。這個迴應似乎表明我可以在我的Form類中完成它,所以this引用仍然引用我的Form實例。否則,如果我的ThreadStart參數是一個不同的類,我不得不傳入對Form實例的引用,這看起來像更多的代碼,對吧?

有人會幫我填寫該回復的上下文嗎?提前致謝!

回答

1

有很多方法可以做到這一點。一個非常簡單,直截了當的版本是使用BackgroundWorker。它專爲這種情況而設計。它有一個在後臺線程中運行的DoWork方法,以及在UI線程中運行完成的工作之後觸發的一個Completed事件(因此您不需要調用invoke或任何更新結果的UI) 。它甚至還內置了用於報告進度的支持(報告進度事件也在UI線程中運行),因此您可以輕鬆更新進度條或狀態文本。

MSDN也有一些examples以及你可以通過一些簡單的搜索找到更多。

通過C#4.0提供的另一種選擇是使用Tasks。你可以開始一個新的任務,它將在後臺線程中運行,然後你可以添加一個將在UI線程中的延續。

下面是一個簡單的例子:

private void button1_Click(object sender, EventArgs e) 
{ 
    Task.Factory.StartNew(() => doStuffInBackground()) 
     .ContinueWith(task => updateUI(), TaskScheduler.FromCurrentSynchronizationContext()); 
} 

private void updateUI() 
{ 
    throw new NotImplementedException(); 
} 

private void doStuffInBackground() 
{ 
    throw new NotImplementedException(); 
} 

當然,你可以做任何你想做的,我有沒有實際的lambda表達式,或者你甚至可以刪除lambda表達式,並把方法有直接,只要你確保簽名是正確的。如果需要,您也可以繼續鏈接這些延續,例如,允許您執行任務1,更新標籤,然後執行任務2,更新標籤等。主要缺點是它不擅長更新進度條經常在一個循環內部,方式可以是BackgroundWorker

+0

哦,真棒。我不知道這存在!非常感謝你。 – Ryan 2012-07-24 16:35:29