[英]Updating the UI from events raised by a background thread
我的WPF應用程序在后台線程上啟動長時間運行的功能,通常通過按鈕單擊/命令,例如
StartCommand = new RelayCommand(async o => await StartAsync(), o => true);
...
private async Task StartAsync()
{
await Task.Run(() => LongRunningFunction());
}
這些長時間運行的函數引發各種事件以向用戶報告進度,更新UI值等。視圖模型處理此類事件並更新綁定屬性,例如:
private void LongRunningProcessProgressChanged(object sender, ProgressEventArgs e)
{
StatusMessageText = string.Format("Progress {0}%", e.Progress);
}
大部分時間這個工作正常,但偶爾我會得到關於從后台線程更新UI的常見例外(“調用線程無法訪問此對象,因為不同的線程擁有它”)),所以我必須將代碼包裝在一個Dispatcher.Invoke(...)
。 我還沒有真正發現過我何時做或不做這種模式的模式,那么任何人都可以對它有所了解嗎?
說實話,我很驚訝上面的代碼可以工作。 斷點確認這些事件處理程序在工作線程上運行,而不是在UI線程上運行,那么為什么我不能一直看到異常呢? 是否與正在更新的財產類型有關?
編輯人們正在提出我已經知道的問題的答案。 再次閱讀我的問題我可能會將讀者與“大多數時候這種方法很好但偶爾會得到通常的例外”這一部分混淆。 我並不是說這是一個間歇性問題 - 我真正的意思是我的一些虛擬機在各自的進度事件處理程序中更新綁定屬性時沒有問題,而其他虛擬機則這樣做。 我懷疑它與屬性類型有關,例如更新字符串屬性但不是ObservableCollection。
我的問題更多的是一個好奇的東西,即為什么一些綁定的屬性可以從ab / g線程更新,而其他人不是。
從后台線程更新UI時,您的代碼應始終拋出異常。 您並不總是看到異常,因為異常發生在后台線程中並且仍未被觀察到 。 對於此類例外
.. TPL需要支持這些異常並持續使用它們,直到消費代碼訪問任務時它們可以被再次拋出。
因此,在從后台任務中拋出異常后,您根本看不到異常。
這個答案揭示了從另一個線程訪問控件時的常見場景。 關於您描述的問題,它實際上取決於您綁定到的屬性類型,如MSDN論壇中所述 :
對基本類型的數據綁定基本上是類型安全的,因為綁定機制在內部使用調度程序為您編組回UI線程。
但是,您需要注意收藏。 例如,ObservableCollection將不處理此問題,因此您需要在UI線程上對集合進行更改。
在這篇博客文章中,您可以找到更多詳細信息。
您面臨的問題是,您正在嘗試更新位於不同線程中的UI元素,您可以嘗試這樣做
App.Current.Dispatcher.Invoke(new Action(() =>
{
// your code
}));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.