简体   繁体   English

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

[英]How to call an async method, and update the UI from there?

Recently I've finished designing a PagedDataGridView custom control, it works very well, but now I'd like to improve its performance. 最近,我已经完成了PagedDataGridView自定义控件的设计,它工作得很好,但是现在我想提高其性能。

How?, well, I've seen some UI blocking when showing new pages. 怎么样?嗯,我在显示新页面时看到了一些UI阻塞。
In short words, this: 简而言之,这是:

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
    }
}


What I'm trying to do (using the async / await pattern): That async method DoPaging pauses until the await 'LoadDataOnGrid' is complete, that way the UI thread is not blocked, be asynchronous. 我正在尝试做的事情(使用异步/等待模式):异步方法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 */
    }
}

I'm just starting to learn about async - await coding, any correction or advice will be greatly appreciated, thanks. 我刚刚开始学习异步-等待编码,非常感谢任何纠正或建议。

Just add async to the button click event handler method and await the call to DoPaging() : 只需将async添加到按钮单击事件处理程序方法中,然后等待对DoPaging()的调用:

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

The difference between doing it like this rather than the way you had that gives the warning (and is in fact why the warning is given) is that if you added any code after the call to DoPaging() in the event handler it would now occur after the task has complete, whereas before it would execute immediately after the call. 这样做与发出警告的方式 (实际上就是给出警告的原因)之间的区别是,如果在事件处理程序中对DoPaging()的调用之后添加了任何代码,则现在会发生在任务完成之后,而在任务执行之前,它将立即执行。

There is a big difference between: 之间有很大的区别:

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

and

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

Exception handling . 异常处理 If the former throws an exception, two things might happen: 如果前者引发异常,则可能会发生两件事:

  1. If you're using .NET 4.0, the swallowed task will be re-thrown from the Finalizer thread and will cause your application to crash 如果您使用的是.NET 4.0,则吞下的任务将从Finalizer线程中重新抛出,并导致您的应用程序崩溃
  2. If you're using .NET 4.5, the task will be swallowed and will go un-noticed and will not be re-thrown at all, thus possibly entering your application in a corrupted state which you wont be aware of. 如果您使用的是.NET 4.5,则该任务将被吞没且不会被注意到, 也将根本不会被重新抛出,因此可能会使您的应用程序进入损坏状态,而您根本不会意识到。

in the latter example, the exception will propogate to the await point, and you can handle it gracefully by adding a try-catch block. 在后一个示例中,异常将传播到await点,您可以通过添加try-catch块来优雅地处理它。

As a side note, i asked you in the comments what kind of work is being done that is blocking your UI thread, and you said that you are making a call to your database to retrieve data. 作为附带说明,我在评论中询问您正在执行的哪些工作正在阻止UI线程,并且您说您正在调用数据库以检索数据。 Work being done against a database is IO bound work, and most providers expose async endpoints to access data, such as Entity Framework, ADO.NET, etc. You can make use of that naturally async behavior by not using any threadpool threads to do the work for you (with Task.Run as you're doing in your example). 针对数据库完成的工作是与IO绑定的工作,并且大多数提供程序都将异步端点公开以访问数据,例如Entity Framework,ADO.NET等。您可以通过不使用任何线程池线程来执行该自然异步行为为您工作(使用Task.Run如您在示例中所做的那样)。 You can do that when you go "async all the way" , and your database query can be used with the await keyword. 您可以在“一路异步”时执行此操作 ,并且您的数据库查询可以与await关键字一起使用。 That way, while the query is retrieving the data, the thread that invoked the query (in your example, the UI thread) is freed and can do more work, thus your UI will stay responsive. 这样,当查询检索数据时,调用查询的线程(在您的示例中为UI线程)将被释放并可以做更多的工作,因此您的UI将保持响应状态。

I suggest you look into that and see if your database provider has those async endpoints. 我建议您调查一下,看看您的数据库提供者是否具有那些异步端点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM