在 2 个等待句子之间更新 UI
本文关键字:之间 更新 UI 句子 等待 | 更新日期: 2023-09-27 18:35:21
我正在尝试在一个(相当简单的)应用程序中实现async-await的东西。我的目标是在等待之间更新一个繁忙的指示器。
我不知道是什么,但我认为我在理解异步等待的东西方面缺少一些必不可少的东西。
private async void StartTest(object obj)
{
try
{
this.IsBusy = true;
this.BusyMessage = "Init..."
await Task.Delay(7000);
var getData1Task = this.blHandler.GetData1Async();
this.BusyMessage = "Retreiving data...";
this.result1 = await getDeviceInfoTask;
this.result2 = await this.blHandler.GetData2Async();
this.BusyMessage = "Searching...";
this.result3 = await this.blHandler.GetData3();
}
finally
{
this.IsBusy = false;
this.BusyMessage = string.empty;
}
}
busyIndicator具有与IsBusy
和BusyMessage
的绑定。执行此代码时,我确实会得到显示"Init..."的 busyIndicator,但它永远不会更改为"检索数据..."或"正在搜索..."。更糟糕的是:UI在执行最终GetData3
时完全冻结。
最有可能
GetData1Async
,GetData2Async
和GetData3
是同步方法(也就是说,我猜虽然它们确实返回了一个Task
,但它们会同步完成所有工作)。 在这种情况下,await
不会挂起该方法(因为返回的Task
将是已完成的任务)。 因此,该方法将作为一个大型同步方法一直持续下去,并且 UI 将永远没有机会更新(因为它在此期间不会泵送任何消息)。
如果您想要的不仅仅是猜测,请向我们展示这三种方法的代码。
听起来您实际上想在后台线程上执行同步方法,然后在 UI 代码中异步等待它完成。
这正是Task.Run()
所做的。
它需要一个委托在 ThreadPool 中运行,然后返回一个await
任务,该任务为您提供结果。
您能否尝试通过调度程序推送消息。
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{ this.BusyMessage = "Retreiving data..."; }));
// Do Something
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{ this.BusyMessage = "Filtering data..."; }));
// Do Something
这是一个工作副本,其中包含我的一些假设。 希望对您有所帮助。 我在正在运行的 WPF 应用程序中对其进行了测试。 请注意,您发布的内容中没有任何保护措施,以确保这不是"双重运行"(无论 IsBusy的值如何,我们都可以开始,StartTest 应该确保这一点)。
public class StackWork : ViewModelBase
{
private class MyHandler
{
private async Task<string> GetDataAsync(string result)
{
return await Task<string>.Run(() =>
{
Thread.Sleep(5000);
return result;
});
}
public async Task<string> GetData1Async()
{
return await GetDataAsync("Data1");
}
public async Task<string> GetData2Async()
{
return await GetDataAsync("Data2");
}
public async Task<string> GetData3()
{
return await GetDataAsync("Data3");
}
}
private bool IsBusy { get; set; }
private string _message = "";
public string BusyMessage
{
get { return _message; }
set { _message = value; RaisePropertyChanged("BusyMessage"); }
}
private MyHandler blHandler = new MyHandler();
private Task<string> getDeviceInfoTask;
private string result1 { get; set; }
private string result2 { get; set; }
private string result3 { get; set; }
public StackWork()
{
getDeviceInfoTask = Task<string>.Run(() =>
{
return ("device info");
});
}
public async void StartTest(object obj)
{
try
{
this.IsBusy = true;
this.BusyMessage = "Init...";
await Task.Delay(7000);
var getData1Task = /*this*/await/*was missing*/ this.blHandler.GetData1Async();
this.BusyMessage = "Retreiving data...";
//assuming this was Task.Run, put that in constructor
this.result1 = getDeviceInfoTask/*this*/.Result/*was missing*/;
this.result2 = await this.blHandler.GetData2Async();
this.BusyMessage = "Searching...";
//This was a little confusing because the name doesn't imply it is
//async, but it is awaited
this.result3 = await this.blHandler.GetData3();
}
finally
{
this.IsBusy = false;
this.BusyMessage = string.Empty;
}
}
}