我正在编写WPF应用程序。我的一个视图模型具有可绑定属性,该属性包含一个可观察的集合:
public ObservableCollection<ItemVm> Items {get; }
有一个漫长的过程,我想运行,修改可观察的集合,但我不想在其工作时阻止UI,所以我想将该过程分成任务列表然后一个接一个地运行它们。由于每个任务都修改了集合,因此这些任务必须在UI线程上运行。我希望找到一种方法来在UI线程上安排它们,允许它执行其他任务(动画,响应用户等),并且只在UI线程不忙时继续执行下一个任务。
让一个方法在UI线程中运行,在UI线程中启动另一个任务我通常会这样做:
task.Start(TaskScheduler.FromCurrentSynchronizationContext());
除此之外,我无法输入任何优先权。我知道我可以使用调度程序来控制优先级,但我更愿意使用任务来完成。
答案 0 :(得分:2)
您可以编写一个自定义TaskScheduler
,使用给定的Task
在Dispatcher
上执行DispatcherPriority
:
class DispatcherTaskScheduler : TaskScheduler
{
private readonly Dispatcher dispatcher;
private readonly DispatcherPriority priority;
public DispatcherTaskScheduler(
Dispatcher dispatcher, DispatcherPriority priority)
{
this.dispatcher = dispatcher;
this.priority = priority;
}
protected override void QueueTask(Task task)
{
dispatcher.BeginInvoke(new Action(() => TryExecuteTask(task)), priority);
}
protected override bool TryExecuteTaskInline(
Task task, bool taskWasPreviouslyQueued)
{
// don't support inlining; inling would make sense if somebody blocked
// the UI thread waiting for a Task that was scheduled on this scheduler
// and we wanted to avoid the deadlock
return false;
}
protected override IEnumerable<Task> GetScheduledTasks()
{
// this is only useful for debugging, so we can ignore it
throw new NotSupportedException();
}
}
使用上述内容,您可以安排Task
这样的假设(假设您在UI线程上,因此Dispatcher.CurrentDispatcher
返回正确的Dispatcher
):
var dispatcherScheduler = new DispatcherTaskScheduler(
Dispatcher.CurrentDispatcher, DispatcherPriority.Background);
var dispatcherTaskFactory = new TaskFactory(dispatcherScheduler);
var task = dispatcherTaskFactory.StartNew(() => /* your code */);
或者,如果您真的更喜欢Start()
:
var task = new Task(() => /* your code */);
task.Start(dispatcherScheduler);