0

我正在尝试在(相当简单的)应用程序中实现异步等待的东西。我的目标是在等待之间更新busyIndi​​cator。

我不知道是什么,但我认为我在理解 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;
    }
}

busyIndi​​cator 与IsBusy和绑定BusyMessage。执行此代码时,我确实让 busyIndi​​cator 显示“ Init... ”,但它永远不会更改为“ Retreiving data... ”或“ Searching... ”。更糟糕的是:ui 在执行 final 时完全冻结GetData3

4

4 回答 4

3

最有可能GetData1Async,GetData2AsyncGetData3是同步方法(也就是说,我猜测虽然它们确实返回 a Task,但它们会同步完成所有工作)。在这种情况下,awaits 不会暂停该方法(因为返回的Task将是一个已完成的任务)。因此,该方法将作为一个大的同步方法一直持续下去,并且 UI 将永远没有机会更新(因为在此期间它没有发送任何消息)。

如果您想要的不仅仅是猜测,请向我们展示这三种方法的代码。

于 2013-10-15T13:47:32.420 回答
2

听起来您实际上想在后台线程上执行同步方法,然后异步等待它在您的 UI 代码中完成。

这正是这样Task.Run()做的。
它需要一个委托在 ThreadPool 中运行,然后返回一个await能够为您提供结果的 Task。

于 2013-10-15T14:54:26.243 回答
0

您可以尝试通过 Dispatcher 推送消息吗?

    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
于 2013-10-15T15:03:24.987 回答
0

这是一份工作副本,其中包含我的一些假设。希望能帮助到你。我在一个正在运行的 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;
        }
    }
}
于 2013-10-15T15:08:41.920 回答