我已经阅读了这篇文章,并尝试尽可能地设置我的应用程序,但它仍然不起作用:
Updating label from module in another thread
在我的情况下,我已经将我的数据库操作抽象为DLL,并且希望将对我的进度条的引用传递给库函数,以便在其工作时进行更新。我的理解是,这正是Async / Await接口的发明。但是,调用的确切语法使我无法理解。我有:
Private Async Sub ButtonImport_Click(sender As Object, e As EventArgs) Handles ButtonImport.Click
Dim importer As DatabaseDataLib.Importation = New DatabaseDataLib.Importation
Dim progress_indicator As Progress(Of Integer) = New Progress(Of Integer)(AddressOf DisplayProgress)
Dim success As Integer = Await Task.Run(Function() importer.ImportDatasetAsync(x, y, z, a, progress_indicator))
If success = 1 Then
Me.Hide()
Else
MsgBox("Something went wrong!", MsgBoxStyle.Exclamation)
End If
End Sub
Public Sub DisplayProgress(percentage As Integer)
Debug.Print("I'm being called!")
ToolStripProgressBarImport.Value = percentage
End Sub
库中的函数签名如下所示:
Public Function ImportDatasetAsync(x As Integer, y As String, z As String, _
a As String, progress_indicator As IProgress(Of Integer)) As Integer
在这个函数中,~18K记录中的每一个都有2个循环。处理完每个问题后,就会调用progress_indicator
回调:
progress_indicator.Report(counter / objects.Count * 100)
这将编译,但随后抛出此错误:
Additional information: Object reference not set to an instance of an object.
显然,这个Task.Run(Function() ...)
表示法会使运行时废话,所以我将调用更改为:
Dim success As Integer = Await importer.ImportDatasetAsync(x, y, z, a, progress_indicator)
这个函数签名:
Public Function ImportDatasetAsync(x As Integer, y As String, z As String, _
a As String, progress_indicator As IProgress(Of Integer)) As Task(Of Integer)
这将通过智能感知检查,但实际编译失败,除非我摆脱我的Return 1
,因为它抱怨Integer
不是System.Threading.Tasks.Task(Of Integer)
。这似乎是我目前担忧的较小,但也许这很重要。摆脱返回值将允许程序最终运行。调用progress_indicator
函数,但调用被堆叠或序列化。 (我不知道正确的术语。)当函数最终完成时,对回调的调用最终会执行。我得到一百左右,然后堆栈溢出。我不知道如何设置这个调用堆栈,以便我得到我期望的行为。
我有点迷茫。我已经在互联网上研究了大约2天的例子,我找不到能使这项工作的神奇咒语。我想,我遗漏了一些基本的东西。在我正在阅读的内容中,有时似乎我应该将实际的数据库调用分解为我创建Async的单独函数,并将Progress对象的更新保留在主循环中,但是,如果这是真的,这几乎是一个抽象层次太深,无法愚弄,我将尝试一种不同的方法来获得一个愚蠢的进度条。啧!