即使使用任务,UI也会冻结批量创建对象

时间:2018-05-01 21:24:52

标签: wpf user-interface asynchronous async-await freeze

我有一个方法OnLoadShapeFilePolygonsCommand(),它从文件中读取多边形(几何)细节并创建一些对象。然后将它们加载到一个可观察的集合中,该集合绑定到数据网格。

虽然所有这些处理,我正在显示进度条。只需添加一个IsIndeterminate属性设置为true的进度条,当加载所有数据时,我将进度条的可见性设置为false

我的问题是,在创建多边形对象时,UI会被冻结(进度条会挂起)。

我在这里做错了吗?请帮忙。

private async void OnLoadShapeFilePolygonsCommand()
{
    // ...
    // some code

    await Task.Factory.StartNew(() =>
    {
        List<Ploygon> collection = new List<Ploygon>();
        foreach (Graphic g in graphics)
        {
            collection.Add(new Ploygon(g,.. .. ..);
        }
        return collection;
    },CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext())
    .ContinueWith((antecedent) =>
    {
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, ThreadStart)delegate ()
        {
            // MapPolygons is observable collection binded to datagrid.
            MapPolygons.AddRange(antecedent.Result);
            //...
        });
        },scheduler);
    }
}

2 个答案:

答案 0 :(得分:0)

为什么将awaitTask.Factory.StartNewContinueWith一起使用?

请改为尝试:

var collection = await Task.Run(
    () => graphics.Select(g => new Ploygon(g,.. .. ..)).ToList());

// MapPolygons is observable collection binded to datagrid.
MapPolygons.AddRange(collection);
...

答案 1 :(得分:-2)

您正在使用Task.Factory.StartNew方法的this overload,提供TaskScheduler作为参数。

您使用静态方法TaskScheduler.FromCurrentSynchronizationContext获取TaskScheduler。正如您可以在文档中阅读的那样,此方法返回与当前TaskScheduler关联的System.Threading.SynchronizationContext

由于您在UI线程上调用Task.Factory.StartNew方法(以及TaskScheduler.FromCurrentSynchronizationContext方法),实际上您正在使用UI线程的TaskScheduler来排队工作。这是冻结用户界面的解释。

一方面注意:TaskCreationOptions.AttachedToParent在这里没用,因为您为父任务指定了此选项。为什么要使用这个选项?

使用快捷方法Task.Factory.StartNew(当然,如果您的目标是.NET 4.5或更高版本),而不是使用Task.Run方法。

或者,使用TaskScheduler.Default代替TaskScheduler.FromCurrentSynchronizationContext()