從任務中訪問 UI 元素
所有 UI 元素都建立並駐留在程式的主執行緒中。 .net 框架執行時禁止從另一個執行緒訪問這些。基本上,這是因為所有 UI 元素都是**執行緒敏感資源,**並且在多執行緒環境中訪問資源需要是執行緒安全的。如果允許此跨執行緒物件訪問,則首先會影響一致性。
考慮這種情況:
我們在任務中進行了計算。任務在主執行緒之外的另一個執行緒中執行。在計算繼續時,我們需要更新進度條。去做這個:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action invokeAction = new Action( () => { progressBar.Value = progress; });
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.Invoke( invokeAction );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
每個 UI 元素都有一個 Dispatcher 物件,它來自 DispatcherObject
祖先(在 System.Windows.Threading
名稱空間內)。Dispatcher 在與 Dispatcher 關聯的執行緒上以指定的優先順序同步執行指定的委託。由於執行是同步的,因此呼叫者任務應該等待其結果。這使我們有機會在排程員代表中使用 int progress
。
我們可能想要非同步更新 UI 元素然後更改 invokeAction
:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action<int> invokeAction = new Action<int>( (i) => { progressBar.Value = i; } )
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.BeginInvoke(
invokeAction,
progress );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
這次我們打包 int progress
並將其用作委託的引數。