为什么我的UI在以这种方式使用System.Threading.Task类时被阻止



在我的ViewModel中,我有以下代码:

Logs = new ObservableCollection<Log>();
Logs = Task.Factory.StartNew(() => mainModel.GetLogs()).Result;

日志是一个非常简单的类,有几个公共属性。

根据我对任务类的理解,以这种方式调用的主模型函数 GetLogs() 应该在单独的线程上运行,当它从数据库中获取记录时,我的 UI 应该是响应的,但事实并非如此,相反,当记录从数据存储中获取时,我的 UI 被阻止了。

我希望有人能解释为什么...蒂亚。

编辑:我对任务类的了解不完整,使用 Task 类的 ContinueWith 方法将确保异步执行,如下文成员回复中所述......

这是因为您在启动异步操作后立即调用ResultResult属性的 getter 阻止当前线程的执行,直到任务完成。

更新:

为了异步获取结果,您需要调用ContinueWith并指定任务完成时将调用的函数:

Task.Factory.StartNew(() => mainModel.GetLogs()).ContinueWith(t => Logs = t.Result);

我认为您不应该像 MSDN 那样使用 Result 属性:

此属性的 get 访问器可确保异步操作在返回之前完成。一旦计算结果可用,它就会被存储起来,并在以后调用 Result 时立即返回。

如果您在任务运行时访问当前线程,它将使当前线程等待。

假设mainModel.GetLogs是线程安全的,你可能想要这样的东西,它在后台线程上调用GetLogs,然后仅在完成获取日志时将Logs设置为结果。TaskScheduler.FromCurrentSynchronizationContext() 确保该部分的执行在 UI 线程上运行,如果您的 UI 绑定到该集合,则需要执行该线程。

Task doStuff = Task.Factory.StartNew<ICollection>(() =>
    {
        return mainModel.GetLogs();
    })
    .ContinueWith((result) =>
    {
        Logs = result;
    }, TaskScheduler.FromCurrentSynchronizationContext());

相关内容