在阅读了许多关于后台工作人员和多线程的 SO 文章后,我有一些工作代码,我想请教您的意见。挑战在于在单独的线程上检索数据并使用内容更新 UI。由于 Invoke 遇到问题,我选择了运行时 BGW;以及 RunWorkerCompleted 的便利性。
你能看一下代码,看看它的方法是否合理和合理?(我没有添加进度更新等)
Public Class BgwArgs 'args object to pass to BGW
Public sSql As String 'query to be run by DoWork
Public dbTable As DataTable 'return data to this table
Public lst As ListBox 'populate this control with returned data
End Class
Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click
'get new BGW, may be multiple BGW's running at a time
Dim myBgw As BackgroundWorker = fGetBgw()
Dim sArgs As New BgwArgs 'set Args
sArgs.sSql = "BHRow" 'just a test string, would really be a query
sArgs.lst = lstBH 'control to populate
myBgw.RunWorkerAsync(sArgs)
End Sub
Private Function fGetBgw() As BackgroundWorker
'create New backgroundworker and addhandlers
Dim newBgw As New BackgroundWorker
myBgw.WorkerReportsProgress = True
myBgw.WorkerSupportsCancellation = True
AddHandler myBgw.DoWork, AddressOf WorkerDoWork
AddHandler myBgw.ProgressChanged, AddressOf WorkerProgressChanged
AddHandler myBgw.RunWorkerCompleted, AddressOf WorkerCompleted
Return newBgw
End Function
Private Sub WorkerDoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
Thread.Sleep(3000) 'kill time as a test
Dim sArgs As BgwArgs = e.Argument
pGetDbTable(sArgs) 'pass in Args to DataQuery
e.Result = sArgs 'set result for use in Completed event
End Sub
Private Sub WorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs)
Dim sArgs As BgwArgs = e.Result
Dim tbl As DataTable = sArgs.dbTable
Dim lb As ListBox = sArgs.lst
Dim thisBgw As BackgroundWorker = CType(sender, BackgroundWorker)
If e.Cancelled = True Then
ElseIf e.Error IsNot Nothing Then
MsgBox(e.Error.Message)
Else
For Each row As DataRow In tbl.Rows
'update UI, bind data here, etc.
lb.Items.Add(row("col1").ToString)
Next
RemoveHandler thisBgw.DoWork, AddressOf WorkerDoWork
RemoveHandler thisBgw.ProgressChanged, AddressOf WorkerProgressChanged
RemoveHandler thisBgw.RunWorkerCompleted, AddressOf WorkerCompleted
Endif
End Sub
Private Sub pGetDbTable(sArgs As BgwArgs)
Dim tbl As New DataTable
'would really run a SQL query here... and return the Datatable
With tbl
.Columns.Add("col1")
Dim i As Integer
For i = 0 To 200
.Rows.Add(sArgs.sSql & i)
Next
sArgs.dbTable = tbl
End With
End Sub