wpf mvvm等待方法阻止UI,同时模拟等待任务延迟不是

时间:2017-07-28 10:47:20

标签: c# wpf multithreading mvvm async-await

当我关注我的用户界面时不冻结

xaml绑定:

<Button Command="{Binding LongRunningCommand}" />

视图模型:

ctor
{
   LongRunningCommand = new DelegateCommand<object>(ProcessLongRunningCommand);
}

public DelegateCommand LongRunningCommand { get; private set; }
private async void ProcessLongRunningCommand(object e)
{
   await Task.Delay(5000);
}

但如果我用真实方法替换Task.Delay,那么我的UI 冻结。这太奇怪了。请看下面的示例:

xaml绑定:

<Button Command="{Binding LongRunningCommand}" />

视图模型:

private readonly IDbAccess _dbAccess;

ctor(IDbAccess dbAccess)
{
   _dbAccess = dbAccess
   LongRunningCommand = new DelegateCommand<object>(ProcessLongRunningCommand);
}

public DelegateCommand LongRunningCommand { get; private set; }
private async void ProcessLongRunningCommand(object e)
{
   var callResult = await _dbAccess.LongRunningMethod();

   //adjust viewmodel observablecollection property which binds to a ListBox with callResult
}

DbAccess impl:

public Task LongRunningMethod(object e)
{
   return Task.Run(() =>
   {
      ...
   }
}

有人可以看到我做错了什么,我在这上面浪费了很多时间......

顺便说一下,我知道async void不是最佳做法,但我找不到使DelegateCommand异步的解决方案。

修改

经过更多的研究,我们得出结论,这是一个'渲染'。问题。 LongRunningCommand是异步的,但渲染和绑定需要时间,它会阻止UI。我不知道如何解决这个渲染问题。

1 个答案:

答案 0 :(得分:4)

这个等待僵局的任务也让我感到很长时间,直到我找到解决方案。

替换

var callResult = await _dbAccess.LongRunningMethod();

var callResult = await _dbAccess.LongRunningMethod().ConfigureAwait(false);

请参阅Stephen Cleary的this blog post了解详情。

请注意,await之后的延续现在将位于不同的调度程序上下文中,因此任何直接更新UI的内容(例如填充可观察集合)都必须编组回UI调度程序。许多MVVM框架都包含实用程序来帮助解决这个问题 - 我使用MVVM Light中的DispatcherHelper类。

如果你正在使用Resharper,你可以安装一个插件来检查是否将ConfigureAwait()添加到每个await语句。