如何调用异步方法,并从那里更新UI

本文关键字:从那里 更新 UI 异步方法 何调用 调用 | 更新日期: 2023-09-27 18:17:06

最近我已经完成了PagedDataGridView自定义控件的设计,它工作得很好,但现在我想提高它的性能。

如何?,嗯,我看到一些UI阻塞时,显示新页面。
简而言之,就是:

public class PagedDataGridView() : UserControl
{
    Paging paging = new Paging();
    public PagedDataGridView()
    {
        paging.LoadDataClientMethod = LoadDataOnGrid;
    }
    private void LoadDataOnGrid()
    {
        // Some heavy set data source here, using functions from 'paging' object
    }
}


我想做什么(使用async/await模式):异步方法DoPaging暂停,直到等待'LoadDataOnGrid'完成,这样UI线程就不会阻塞,是异步的。

// Class that handles paging methods, variables,
// also offers navigation controls, such as buttons, labels, etc.
internal class Paging
{
    // Represents the method that code client uses to load its own data
    public Action LoadDataClientMethod;
    // HERE: 
    private async Task DoPaging()
    {
        // some calculations
        if (LoadDataClientMethod != null)
        {
            // I realizad that calling Run method, runs it out of context
            // How to run this method, and update the UI
            await Task.Run(() => LoadDataClientMethod());
        }
        // Update controls, showing current page, etc
        UpdateUI();
    }
    // Navigation buttons
    private void btnGoNextPage(object sender, EventArgs e)
    {
        // go next page calculations
        // Then how to call the async method
        DoPaging(); // -> doing this, VS shows a warning:
        /* Because this call is not awaited, the current method
           continues to run before the call is completed */
    }
}

我刚刚开始学习async - await编码,任何更正或建议将非常感激,谢谢。

如何调用异步方法,并从那里更新UI

private void btnGoNextPage(object sender, EventArgs e)
{
    DoPaging();
}

private async void btnGoNextPage(object sender, EventArgs e)
{
    await DoPaging();
}
异常处理

。如果前者抛出异常,可能会发生两种情况:

  1. 如果你使用的是。net 4.0,吞下的任务将从Finalizer线程重新抛出,并将导致你的应用程序崩溃
  2. 如果你使用的是。net 4.5,任务将被吞下并且不会被注意到,并且将不会被重新抛出,因此可能以您不知道的损坏状态进入您的应用程序。

在后一个例子中,异常将传播到await点,您可以通过添加try-catch块来优雅地处理它。

作为旁注,我在评论中问你正在做什么样的工作是阻塞你的UI线程,你说你正在调用你的数据库来检索数据。针对数据库所做的工作是IO绑定的工作,大多数提供程序都公开异步端点来访问数据,例如Entity Framework、ADO。净等。您可以通过不使用任何线程池线程来为您完成工作(使用Task.Run,正如您在示例中所做的那样)来利用这种自然的异步行为。当您执行"async all the way"时可以这样做,并且您的数据库查询可以与await关键字一起使用。这样,当查询检索数据时,调用查询的线程(在您的示例中是UI线程)被释放并可以做更多的工作,因此您的UI将保持响应。

我建议您查看一下,看看您的数据库提供商是否有这些异步端点。

只需将async添加到按钮单击事件处理程序方法中,并等待对DoPaging()的调用:

private async void btnGoNextPage(object sender, EventArgs e)
{
    await DoPaging();
}

这样做与您给出警告的方式(实际上是给出警告的原因)之间的区别在于,如果您在事件处理程序中调用DoPaging()之后添加任何代码,它现在将在任务完成后发生,而在调用后立即执行之前。