被触发的异步事件

时间:2015-12-02 07:25:07

标签: vb.net

我正在编写一个同时运行多个线程的应用程序。 每个线程与Web服务器通信并下载不同数量的数据。 我想显示应用程序中所有线程的总进度。

每个线程每下载1兆字节就会引发一个事件:

 RaiseEvent My_Event(Size_Downloaded as double,Total_Size as double)

有没有办法显示主表单中下载的总数而不会出现跨线程错误?

它不必是瞬时的,所以定时器可能有用吗?

3 个答案:

答案 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()表达式)会为您做这些。

希望这有帮助!

相关问题