c# - 异步/等待 Windows 窗体应用程序

标签 c# asynchronous async-await

我正在尝试在我的应用程序中学习和实现 async/await 关键字。我正在使用 API 获取数据,然后将它们显示在我的表单上。当我尝试从控制台应用程序调用方法时没有问题。但是,如果我从 Form_Shown 事件调用我的异步方法,也没有异常,但方法不起作用。

所以我在 Form_Shown 事件上调用我的 RefreshOrLoadDataToCache() 方法。

private async void LogTimeReport_Shown(object sender, EventArgs e)
{
    // Some syncronous operations

    RefreshOrLoadDataToCache(); // Async methods in it 

    // Some syncronous operations
}

在我的这个方法中创建了一个任务并等待它。

private async void RefreshOrLoadDataToCache()
{
    if (IsNeededToCallAPI())
    {
        var taskForTimeEntries = LoadTimeEntriesTemp();
        Task.WhenAll(taskForTimeEntries);

        DataTable dtTimeEntriesTemp = taskForTimeEntries.Result;
        DataTable dtEventsTemp = LoadEventsTemp();

        dtTimeEntriesTemp.Merge(dtEventsTemp);
    }
    else
        BindGridViews();
}

这是我的异步方法。

 private async Task<DataTable> LoadTimeEntriesTemp()
 { 
     TimeEntryHandler timeHandler = new TimeEntryHandler();

     TimeEntryResponse response = await timeHandler.GetTimeEntries();

     DataTable dt = DatatableHelper.ToDataTable<TimeEntry>(response.TimeEntries);

     foreach (DataRow drow in dt.Rows)
     {
        // Some operations on DataTable
     }
     return dt;
 }

在这种方法中,我连接到 API 并获得结果。我认为我的问题是关于这种方法。因为当我从控制台应用程序调用此方法时,它会返回数据。但是从表单申请它等待很长时间但没有结果或异常。

private async Task<TimeEntryResponse> GetTimeEntries()
{
    using (var client = new AuthorizedHttpClient(_client))
    {
        var data = await client.GetAsync<TimeEntryResponse>(parameters);

        if (data.StatusCode == HttpStatusCode.OK)
        {
            var response = (TimeEntryResponse)data.ContentObj;
            response.Pages = int.Parse(data.Headers.GetValues("X-Pages").First());
            response.Page = int.Parse(data.Headers.GetValues("X-Page").First());
            response.TotalRecords = int.Parse(data.Headers.GetValues("X-Records").First());
            return response;
        }
        return new TimeEntryResponse() { TimeEntries = null, STATUS = "ERROR" };
    }
}

我认为 Windows 窗体上的异步调用缺少一些东西。如何修复我的代码?

最佳答案

你的代码有几个问题

  1. 您将一个方法标记为async,但您不等待其中的操作。您目前这样做是因为 RefreshOrLoadasync void。它实际上需要是 async Task,其中底层返回的任务是正在进行的异步操作。然后,返回的 Task 应该等待:

    private async void LogTimeReport_Shown(object sender, EventArgs e)
    {
        // Some syncronous operations
    
        await RefreshOrLoadDataToCache(); // Async methods in it 
    
        // Some syncronous operations
    }
    
  2. RefreshOrLoad 是一种异步方法。您使用 Task.WhenAll,它用于异步等待多个任务,但您也不需要 await。然后,您调用 .Resultwhich causes your code to effectively deadlock .所需要做的就是等待任务从 LoadTimeEntriesTemp 返回:

    private async Task RefreshOrLoadDataToCache()
    {
        if (IsNeededToCallAPI())
        {
            DataTable dtTimeEntriesTemp = await LoadTimeEntriesTemp();
            DataTable dtEventsTemp = LoadEventsTemp();
    
            dtTimeEntriesTemp.Merge(dtEventsTemp);
        }
        else
            BindGridViews();
    }
    

    我还注意到您应该将 *Async 后缀与您的异步方法一起使用。

修复这些问题时,您会发现代码的行为符合预期,一直是异步的。

关于c# - 异步/等待 Windows 窗体应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31892043/

相关文章:

c# - Task.Delay(0) 不是异步的

c# - 如何在每个实现的异步中抛出取消异常?

javascript - 两行相同代码的区别

c# - 根据基类的 Equals() 使派生类相等

javascript - Django:防止重复对象创建的策略

javascript - 如何对 .then promise 应用延迟?

javascript - Sequelize 等待直到循环

c# - 使用项目中包含的图像

c# - 从 shell 运行的 ffmpeg 运行正常,但在 .NET 中调用时运行不正常

c# - 给定一个 ContainerBuilder,我可以注册一个缺失的依赖处理程序吗?