如何调用异步方法,并从那里更新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编码,任何更正或建议将非常感激,谢谢。
private void btnGoNextPage(object sender, EventArgs e)
{
DoPaging();
}
和
private async void btnGoNextPage(object sender, EventArgs e)
{
await DoPaging();
}
异常处理。如果前者抛出异常,可能会发生两种情况:
- 如果你使用的是。net 4.0,吞下的任务将从
Finalizer
线程重新抛出,并将导致你的应用程序崩溃 - 如果你使用的是。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()
之后添加任何代码,它现在将在任务完成后发生,而在调用后立即执行之前。