当我关注我的用户界面时不冻结:
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。我不知道如何解决这个渲染问题。
答案 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语句。