我看到一些奇怪的行为,我启动的两个线程之一的RunWorkerCompleted事件没有被调用,具体取决于我如何调用它们。查看下面的代码,以及触发线程的两种方法,good()和bad()。
Public Class Form1
Private WithEvents bw As System.ComponentModel.BackgroundWorker
Private WithEvents bw2 As System.ComponentModel.BackgroundWorker
Private starts As Integer = 0
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
starts += 1
Threading.Thread.Sleep(e.Argument)
End Sub
Private Sub bw_Completed(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
MessageBox.Show("Ending " + starts.ToString())
End Sub
Private Sub bad()
bw = New System.ComponentModel.BackgroundWorker()
bw.RunWorkerAsync(5000)
Threading.Thread.Sleep(500)
bw = New System.ComponentModel.BackgroundWorker()
bw.RunWorkerAsync(5)
End Sub
Private Sub good()
bw2 = New System.ComponentModel.BackgroundWorker()
AddHandler bw2.DoWork, AddressOf bw_DoWork
AddHandler bw2.RunWorkerCompleted, AddressOf bw_Completed
bw2.RunWorkerAsync(500)
bw2 = New System.ComponentModel.BackgroundWorker()
AddHandler bw2.DoWork, AddressOf bw_DoWork
AddHandler bw2.RunWorkerCompleted, AddressOf bw_Completed
bw2.RunWorkerAsync(5)
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'good()
bad()
End Sub
End Class
在这两种情况下,都会为两个线程调用DoWork事件。但在bad()情况下,只有第二个线程触发RunWorkerCompleted事件。这显然是由于我使用VB处理事件的两种不同方式。我正在寻找这种行为的解释,最好是链接到一些文档,可以帮助我更好地理解如何在VB中处理这些事件。对我来说似乎很奇怪,只是在这里重用一个变量名称似乎要么在它完成之前处理该线程,要么只是让它停止触发事件。
答案 0 :(得分:1)
这个自动取消订阅记录在哪里?
在Visual Basic语言规范中,您可以download from Microsoft创建一个文档。第9.6.2章“WithEvents变量”说明了这一点:
由WithEvents声明创建的隐式属性负责挂钩和取消挂钩相关的事件处理程序。将值赋给变量时,属性首先在当前变量中的实例上调用事件的remove方法(取消现有事件处理程序,如果有的话)。接下来进行赋值,并且属性为变量中的新实例上的事件调用add方法(连接新的事件处理程序)。
粗体短语描述了您看到的行为。它的工作方式非常重要。如果没有,那么你永远不能取消订阅一个事件,并且事件订阅将无限制地堆积。