我正在编写一个同时运行多个线程的应用程序。 每个线程与Web服务器通信并下载不同数量的数据。 我想显示应用程序中所有线程的总进度。
每个线程每下载1兆字节就会引发一个事件:
RaiseEvent My_Event(Size_Downloaded as double,Total_Size as double)
有没有办法显示主表单中下载的总数而不会出现跨线程错误?
它不必是瞬时的,所以定时器可能有用吗?
答案 0 :(得分:3)
正如Rene所说,取决于你得到的交叉线程错误。如果你得到任何跨线程的UI调用错误,那么处理它的最佳方式是imo,是通过代理。
作为一个例子,我只是快速写下这个:
这将导致跨线程UI错误。
Private Sub DoThis()
Dim bgw As New BackgroundWorker
AddHandler bgw.DoWork, AddressOf bgwDoWork
AddHandler bgw.RunWorkerCompleted, AddressOf bgwDone
bgw.RunWorkerAsync(1)
End Sub
Private Sub bgwDoWork(sender As Object, e As DoWorkEventArgs)
Dim i As Integer = e.Argument
RTB.AppendText(CInt(i + 2).ToString)
End Sub
但是,使用delegate sub,我们可以访问主线程上的控件:
Private Sub DoThis()
Dim bgw As New BackgroundWorker
AddHandler bgw.DoWork, AddressOf bgwDoWork
AddHandler bgw.RunWorkerCompleted, AddressOf bgwDone
bgw.RunWorkerAsync(1)
End Sub
Private Delegate Sub UpdateText(item As String)
Private Sub Update_RTB(item As String)
If RTB.InvokeRequired Then
RTB.Invoke(New UpdateText(AddressOf Update_RTB), item)
Else
RTB.AppendText(item)
End If
End Sub
Private Sub bgwDoWork(sender As Object, e As DoWorkEventArgs)
Dim i As Integer = e.Argument
Update_RTB(CInt(i + 2).ToString)
End Sub
如果您需要我进一步澄清这一点,请不要告诉我。
干杯。
答案 1 :(得分:3)
您可以更改事件签名并添加线程的ID 并使用计时器显示总计
Dim _info As New ConcurrentDictionary(Of Integer, DLoadInfo)
Sub MyEvent(id As Long, Size_Downloaded As Double, Total_Size As Double)
Dim v = New DLoadInfo() With
{
.SizeDownloaded = Size_Downloaded,
.TotalSize = Total_Size
}
_info.AddOrUpdate(id, v,
Function(key, oldValue)
Return v
End Function
)
End Sub
Private Sub TimerDisplay_Tick(sender As Object, e As EventArgs)
Dim sizeDownloaded, totalSize As double
For Each o As DLoadInfo In _info.Values
sizeDownloaded += o.SizeDownloaded
totalSize += o.TotalSize
Next
TextBoxSizeDownloaded.Text = sizeDownloaded
TextBoxTotalSize.Text = totalSize
End Sub
Class DLoadInfo
Public property SizeDownloaded As Double
Public property TotalSize As Double
End Class
答案 2 :(得分:2)
这是我用于多线程事件的一个相当简单的解决方案:
Private Sub ThreadSafeRaise_MyEvent(Size_Downloaded As Double, Total_Size As Double)
If Me.InvokeRequired = True Then
Me.Invoke(Sub() ThreadSafeRaise_MyEvent(Size_Downloaded, Total_Size))
Else
RaiseEvent My_Event(Size_Downloaded, Total_Size)
End If
End Sub
如果需要调用表单(此代码中为Me
),则该方法使用lambda来调用它,然后再次执行该方法。但是这次调用表单时,可以正常引发事件。
要举起活动,您只需要致电(不需要< >
):
ThreadSafeRaise_MyEvent(<size downloaded here>, <total size here>)
那就是它!无需进一步调用,以这种方式提升事件是线程安全的。您也不需要声明自己的任何代表,因为lambda(Sub()
表达式)会为您做这些。
希望这有帮助!