c# - 如何让任务返回到 WPF 中的 UI 线程

标签 c# wpf async-await task

背景:我在 C# 方面比较有经验,但对 WPF 完全陌生。

我有一个 WPF 应用程序,将在内部用于一些简单的监控。我有一个数据库调用,然后返回的数据显示在 TreeView 中, 当发生这种情况时,在数据返回之前会有一个覆盖层显示“正在加载...”。我当前的实现如下所示:

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 行我得到异常“调用线程无法访问此对象,因为另一个线程拥有它。”。

我怀疑这与任务的同步上下文有关(如果我没记错我的技术演示的话),但我不知道如何控制它来继续 在同一线程上恢复。

最佳答案

您可以将 TaskScheduler 与延续任务相关联,以强制在 UI 上设置设置 ContentVisibility 属性的委托(delegate)主题:

var overlayTask = Task.Delay(250, token).ContinueWith(_ => {
    Overlay.Content = overlayMessage;
    Overlay.Visibility = Visibility.Visible;
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

关于c# - 如何让任务返回到 WPF 中的 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52182793/

相关文章:

c# - 将 UserControl 的 SelectedValue 绑定(bind)到 ViewModel

c# - 计算 DataGrid 中可见行的数量

c# - 超时模式——Thread.Abort 到底有多糟糕?

c# - ASP.NET 中同一 gridview 行中的多个记录

c# - 使用导体和事件聚合器的分层导航

c# - 如何在不等待完成的情况下启动异步方法?

c# - 顺序等待 VS 连续等待

javascript - 从 promise 中返回 Unresolved promise

c# - Unity3D:一旦玩家在无尽的运行者中在 z 轴上通过障碍物预制件的实例,我该如何销毁它们?

c# - 通过 C# 使用 I2C 设备