最近,我一直在使用system.form.timer
中的UI thread
。我已经注意到虽然我可以在后台线程上停止计时器,但我无法启动它,除非我使用BeginInvoke
,即使我没有收到cross-threading exception
。但是在system.timers.timer
上似乎我可以从计时器创建的后台线程中停止并启动它。为什么是这样?允许system.form.timer
被停止,但是没有从后台线程启用?这对我来说有点奇怪。
不工作
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim BW As BackgroundWorker = New BackgroundWorker
AddHandler BW.DoWork, AddressOf CheckTimer
BW.RunWorkerAsync()
End Sub
Private Sub CheckTimer()
Timer1.Stop()
Timer1.Start()
MsgBox("Stopped and Started Timer")
End Sub
WORKS
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim BW As BackgroundWorker = New BackgroundWorker
AddHandler BW.DoWork, AddressOf CheckTimer
BW.RunWorkerAsync()
End Sub
Private Sub CheckTimer()
Timer1.Stop()
Me.BeginInvoke(New TimerStart(AddressOf TimerStartFunction))
MsgBox("Stopped and Started Timer")
End Sub
Private Delegate Sub TimerStart()
Private Sub TimerStartFunction()
Timer1.Start()
End Sub
WORKS
Dim aTimer As System.Timers.Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
aTimer = New System.Timers.Timer(5000)
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
aTimer.Enabled = True
End Sub
Sub OnTimedEvent()
aTimer.Stop()
aTimer.Start()
MsgBox("Stopped and Started Timer")
End Sub
答案 0 :(得分:5)
Winforms Timer类有些线程安全,不足以让你开心。当您调用其Start()方法时,它会创建一个隐藏窗口,将WM_TIMER消息转换为Tick事件。
当您在工作线程上执行此操作时,您往往会遇到问题,这些WM_TIMER消息仅在线程运行消息循环时调度。工作线程通常不这样做,它们不调用Application.Run()。所以计时器不会打勾。
调用Stop()方法是好的,它知道如何在错误的线程上运行代码时找回隐藏的窗口。您在BeginInvoke()中找到的解决方法可以正常工作,因为它现在可以在UI线程上正确调用Start()并获取使用正确的所有者线程创建的隐藏窗口。 System.Timers.Timer没有这个问题,它不依赖于WM_TIMER来勾选,而是使用System.Threading.Timer。由CLR管理的专用工作线程支持哪一个。请注意,此计时器非常危险。在一个工作线程上调用MsgBox()从根本上说是错误的。用户永远不会看到它的高赔率,因为它将在UI窗口后面。
这解释了,我无法提供更好的建议,因为我无法看到你真正想做的事情。小心,你正在玩火。