将任务调度到低优先级的UI线程

时间:2014-10-22 14:27:49

标签: wpf multithreading task-parallel-library

我正在编写WPF应用程序。我的一个视图模型具有可绑定属性,该属性包含一个可观察的集合:

public ObservableCollection<ItemVm> Items {get; }

有一个漫长的过程,我想运行,修改可观察的集合,但我不想在其工作时阻止UI,所以我想将该过程分成任务列表然后一个接一个地运行它们。由于每个任务都修改了集合,因此这些任务必须在UI线程上运行。我希望找到一种方法来在UI线程上安排它们,允许它执行其他任务(动画,响应用户等),并且只在UI线程不忙时继续执行下一个任务。

让一个方法在UI线程中运行,在UI线程中启动另一个任务我通常会这样做:

task.Start(TaskScheduler.FromCurrentSynchronizationContext());

除此之外,我无法输入任何优先权。我知道我可以使用调度程序来控制优先级,但我更愿意使用任务来完成。

1 个答案:

答案 0 :(得分:2)

您可以编写一个自定义TaskScheduler,使用给定的TaskDispatcher上执行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);