從任務中訪問 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 並將其用作委託的引數。