【问题标题】:Async loading for winformswinforms的异步加载
【发布时间】:2014-12-18 11:05:00
【问题描述】:

在 (Android) 应用程序中,在用户与界面交互时加载和构建 ListViews 是很常见的。然而,在 Winforms 中,趋势似乎是单击按钮并等待结果完全加载,然后用户才能继续在应用程序中导航。

由于我当前使用的数据库访问速度很慢,我想在异步方法中使用数据库,以使用户能够在数据未完全加载和显示的情况下继续与界面交互。

例如,我想在我的 Form_Load 事件中启动一个异步方法来继续收集数据。当这个方法完成时,我想将数据绑定到一些控件——这(现在)根本不会改变功能。因此,我希望用户在处理应用程序时不要注意到任何差异(除了是否显示数据)。

我应该在哪里放置 await 关键字来完成此操作?我不能将它放在我的 Load 事件中,因为这需要完成才能使应用程序“正常”运行。

是否甚至可以使用异步方法让 Windows 窗体完全反应而并非所有方法都完成,或者我是否出于我的目的查看“错误”功能?

提前谢谢你。

编辑:根据 Srirams 的提示,我将 load-event 本身设置为一个运行良好的异步 sub。下面是一些显示所需行为的简单示例代码:

Public Class DelayedLoadingWindow

    Private Async Sub DelayedLoadingWindow_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim awaitedResultOne As Task(Of String) = GetDataOneAsync()
        Label1.Text = Await awaitedResultOne
        Dim awaitedResultTwo As Task(Of String) = GetDataTwoAsync()
        Label2.Text = Await GetDataTwoAsync()
        Dim awaitedResultThree As Task(Of String) = GetDataThreeAsync()
        Label3.Text = Await GetDataThreeAsync()
        Me.Text = "DONE"
    End Sub

    Public Async Function GetDataOneAsync() As Task(Of String)
        Await Task.Delay(2000)
        Return "Async Methods"
    End Function

    Public Async Function GetDataTwoAsync() As Task(Of String)
        Await Task.Delay(2000)
        Return "are"
    End Function

    Public Async Function GetDataThreeAsync() As Task(Of String)
        Await Task.Delay(2000)
        Return "running!"
    End Function
End Class

【问题讨论】:

  • 为什么不使用BackgroundWorker
  • @H W:我已经用测试项目检查了我的代码并且它运行良好。

标签: c# .net vb.net asynchronous visual-studio-2013


【解决方案1】:

我应该在哪里放置 await 关键字来完成此操作?一世 无法将它放在我的 Load 事件中,因为这需要完成 应用程序行为“正常”。

为什么不能在加载事件处理程序中等待?如果你用async修饰符标记方法,你可以这样做。

private async void Form_Load(object sender, EventArgs e)
{
    //Do something
    var data = await GetDataFromDatabaseAsync();
    //Use data to load the UI
}

这样,您可以保持 UI 响应并异步执行耗时的工作。 GetDataFromDatabaseAsync 必须是异步的(不应阻塞调用线程)。

如果这不能回答您的问题,请更具体。

【讨论】:

  • 虽然这不会阻塞 UI,但在事件处理程序完成之前,相关表单肯定不会加载,直到 GetDataFromDatabaseAsync() 完成。
  • @BenRobinson 从 OP 所说的 因此我希望用户不要注意到任何差异(除了显示或不显示的数据) 我猜这很好。你还能做些什么呢?
  • @BenRobinson:不,WinForms 在遇到第一个await 时认为Form_Load 事件“完成”。这是一个完全合适的解决方案;只需确保表单在第一个await之前初始化为“空状态”UI,然后代码之后第一个await应该只是更新 UI 以包含数据。
  • @TommyMoore 你是什么意思?你确定你对 async/await 足够了解吗?是什么让 Task 成为 async/await 所不具备的强大而整洁的功能?
  • @HW 欢迎。 StephenCleary's blog 是开始学习 async/await 的好地方。干杯!。
【解决方案2】:

你可以使用BackgroundWorker控件,

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

您只需将 BackgroundWorker 控件放在表单上(在我们的例子中为 backgroundWorker1),BackgroundWorker 控件还支持取消、RunWorkerCompleted 等。

private SlowLoadingForm frm;

private void startAsyncButton_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    frm = new SlowLoadingForm();
    frm.show();
    Application.Run(frm);
}

【讨论】:

  • DoWork 在与 UI 线程不同的线程中工作,那里没有消息循环。这将以惊人的方式失败。
  • @Steve:我只是忘记添加 Application.Run(frm),现在我已经更新了我的代码,它现在可以正常工作了,我已经用我的测试项目检查了它。谢谢你的指正。
  • 不反对你,但这仍然是错误的stackoverflow.com/questions/3892189/…
  • @Steve:史蒂夫的代码有什么问题,我很想知道,我已经用我的测试项目对其进行了测试,如果你愿意,我可以发送给你。 pl。让我知道问题所在。
  • @Vaibhav 现在您的DoWork 事件除了发送使BackgroundWorker 无用的消息外,不能做任何其他工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多