【发布时间】:2018-03-17 00:38:02
【问题描述】:
假设我有一个长时间运行的 Web API 调用(异步方法),它返回一个字符串。
这两种解决方案之间是否存在最佳实践,可以在 WPF 属性中显示结果而不阻塞 UI?或者还有别的吗?
注意:两种解决方案都不会冻结 UI,我已经查看了 How to call an async method from a getter or setter? 和 Async property in c# 的帖子。
我的 Wep API
private async Task<string> GetAsyncProperty()
{
string result = "Async Property Value";
// Web api call...
await Task.Delay(TimeSpan.FromSeconds(10));
return result;
}
解决方案 A
XAML:
<TextBlock Text="{Binding Path=AsyncPropertyA, UpdateSourceTrigger=PropertyChanged}" />
视图模型:
public MyConstructor()
{
Task task = SetAsyncPropertyA();
}
private async Task SetAsyncPropertyA()
{
this.AsyncPropertyA = await GetAsyncProperty().ConfigureAwait(false);
}
解决方案 B
XAML:
<TextBlock Text="{Binding Path=AsyncPropertyB, UpdateSourceTrigger=PropertyChanged, IsAsync=True, FallbackValue='Loading B...'}" />
视图模型:
public string AsyncPropertyB
{
get
{
return GetAsyncPropertyB();
}
}
private string GetAsyncPropertyB()
{
return Task.Run(() => GetAsyncProperty()).Result;
}
注意:在解决方案 B 中,我可以添加在解决方案 A 中不起作用的 FallbackValue,并可能在 Task.Run 的 ContinueWith 中添加一些其他 UI 更新。
【问题讨论】:
-
请注意,在 Bindings 上设置
UpdateSourceTrigger=PropertyChanged是没有意义的。它仅在实际更新其源属性的绑定中有效,即 TwoWay 或 OneWayToSource 绑定。 -
在B中,从属性getter返回
GetAsyncProperty().Result就足够了。 -
谢谢!如果我想显示一个绑定到布尔值的微调器以了解更新何时完成,我可以在没有
Task.Run(...).ContinueWith(x => IsLoading = false...的情况下做到吗? -
.Result 是阻塞的,可能导致 WPF/UI 环境中的死锁。不要使用 .Result 或 .Wait!
-
@PeterBons 如果我在 XAML 中使用
IsAsync=True则不会。即使我使用了IsAsync,是否还有可能导致死锁?
标签: c# wpf asynchronous data-binding async-await