从任务中访问 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
并将其用作委托的参数。