c# - 如何让任务返回到 WPF 中的 UI 线程
问题描述
背景:我在 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
我得到异常“调用线程无法访问此对象,因为不同的线程拥有它。'”。
我怀疑这与任务的同步上下文有关(如果我没记错我的技术演示),但我不知道如何控制它以使继续在同一个线程上恢复。
解决方案
您可以将 aTaskScheduler
与延续任务相关联,以强制设置Content
和Visibility
属性的委托在 UI 线程上设置:
var overlayTask = Task.Delay(250, token).ContinueWith(_ => {
Overlay.Content = overlayMessage;
Overlay.Visibility = Visibility.Visible;
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
推荐阅读
- python - MATLAB转换为python?由于数组的形状导致python中的错误
- javascript - 在按钮单击时反应获取数据
- java - IText - 文本从 PDF 中消失
- python-3.x - 如何使用管理面板将照片添加到模板?
- vaadin - 以编程方式为 Vaadin 图表系列创建颜色
- vb.net - 以日期降序显示 NLog
- laravel-backpack - date_picker 字段不显示来自 laravel 8 背包客 4.1 中数据库的值
- c# - 在 Restsharp.AddParameter 和 .AddJsonBody 中添加 string_array
- c++ - 字符串添加期间的未知字符
- sql - 扫描列以获取值并使用结果选择其他列