2009年9月23日 星期三

在WPF中跨執行緒非同步的元件操作

透過在WPF中跨執行緒的元件操作所說的方式
可以很容易的在不同的執行緒(Thread)中更新使用者介面(UI)
不過如果當更新的動作太過頻繁,就會發現整個反應變慢
原因就是Dispatcher.Invoke()這個函式是同步的更新
也就是當呼叫的時候會等待更新完成才會回傳
這時候可以改採用非同步的方法,最簡單的方式就是改用BeginInvoke()
假設被用到的函式是

void Func(Type Param);

原本呼叫的地方(另一個執行緒中)本來應該是

Func(p);

直接改成(注意這邊的參數順序跟Invoke不太一樣)

Dispatcher.BeginInvoke(new Action<Type>(Func),
DispatcherPriority.Normal, p);

如此一來,呼叫端的程式就不會等到更新完成才接下去做事
這時候會發現被呼叫的頻率回覆了,但可能會延遲一段時間後一次更新

另外如果是一些特別的情形,還有幾種主動的非同步方式
例如使用這個函式的地方並不是固定的
那可以先檢查是否有處理的權限再作呼叫

if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action<Type>(Func), p);
}
else
{
Func(p);
}

這樣一來,就不是每一次都會把更新動作放進更新的序列中
而是將可以執行的部分直接動作,只做必要的Invoke
而這時要注意不要用BeginInvoke,因為執行順序可能會不符預期

另外一種就更特別,如果其實希望做的更新可以整合在一起一次做的話
比如原本是用迴圈呼叫Invoke來做更新
那就看看可不可以將迴圈放進Invoke的函式裡面
也就是一次更新多一些,而不是放一堆更新任務到序列中

--
參考資料
Dispatcher.BeginInvoke 方法
Invoke != Dispatcher.Invoke
Dispatcher.CheckAccess 方法

沒有留言:

張貼留言