【发布时间】:2019-02-10 11:04:12
【问题描述】:
背景:我在 C# 方面比较有经验,但对 WPF 完全陌生。
我有一个 WPF 应用程序,它将在内部用于一些简单的监控。我有一个数据库调用,然后返回的数据显示在树视图中, 当这种情况发生时,在数据返回之前会有一个覆盖显示“正在加载...”。我当前的实现如下所示:
await WithOverlay("Loading...", async () =>
{
MyControl.Items = await _database.Retrieve(messageSummary.Id);
});
WithOverlay 看起来像这样:
private async Task WithOverlay(string overlayMessage, Func<Task> func)
{
Overlay.Content = overlayMessage;
Overlay.Visibility = Visibility.Visible;
await func();
Overlay.Visibility = Visibility.Hidden;
}
现在,这工作得很好,但是因为很多时候(取决于用户在应用程序的其他地方查看的具体内容)数据库调用真的回来了
很快,“正在加载...”叠加层只是令人讨厌的闪烁。这只是一件小事,但它困扰着我,所以我决定我可以通过放一个小东西来解决它
在叠加层出现之前延迟;比如说,一刻钟。这是我尝试修改WithOverlay 方法:
private async Task WithOverlay(string overlayMessage, Func<Task> func)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var overlayTask = Task.Delay(250, token).ContinueWith(_ => {
Overlay.Content = overlayMessage;
Overlay.Visibility = Visibility.Visible;
});
await func();
if (token.CanBeCanceled) tokenSource.Cancel();
Overlay.Visibility = Visibility.Hidden;
}
我的想法是:
- 创建一个延迟为 250 毫秒的任务,完成后将显示叠加层
- 等待包装函数
- 当被包装的函数完成时,如果覆盖任务还没有完成则取消它
- 隐藏叠加层(无论其当前状态如何)
很遗憾,虽然这不起作用;在Overlay.Content = overlayMessage 行上,我收到异常“调用线程无法访问此对象,因为另一个线程拥有它。'”。
我怀疑这与任务的同步上下文有关(如果我没记错我的技术演示),但我不知道如何控制它以获得继续 在同一线程上继续。
【问题讨论】:
-
您可以尝试
DispatcherTimer代替任务或使用Dispatcher.Invoke进行编组。 -
您必须同时等待
func和overlayTask,使用WhenAny()。但我认为使用 Timer 更清洁。 -
恕我直言,这是对 async/await 的最佳解释,它确实对我有所帮助,也可能对您有所帮助:youtube.com/watch?v=0qiB3oW_nd8
-
@bommelding 感谢您的评论。我很好奇你将如何使用计时器来实现这一点,你介意详细说明一下吗?
-
当你完成这个工作后,一个需要 260 毫秒的数据库调用怎么样?您在这里并没有真正解决任何问题,只是将问题转移了。
标签: c# wpf async-await task