我正在开展一个项目,要求我对外部设备生成的5个独立事件做出反应,然后在一定延迟后做一些事情。这些事件通常会一次发生一次,但有时可能同时发生。这是一个坏主意,如果是这样,为什么?
Imports System.Windows.Threading
Class MainWindow
Private TimerList As List(Of DispatcherTimer)
Private Sub Window_Loaded(ByVal sender As System.Object,
ByVal e As ystem.Windows.RoutedEventArgs) Handles MyBase.Loaded
TimerList = New List(Of DispatcherTimer)
'Create 5 timers for the 5 events from external device
For i As Integer = 1 To 5
TimerList.Add(
New DispatcherTimer(TimeSpan.FromSeconds(10), DispatcherPriority.Normal,
New System.EventHandler(AddressOf tmr_Tick),
Me.Dispatcher) With {.Tag = i}
)
Next
End Sub
Public Sub SomeEventFromExternalDevice(ByVal ID As Integer) 'handles...
Dim CurTimer = TimerList.Find(Function(x) x.Tag = ID)
If Not CurTimer Is Nothing Then
CurTimer.Start()
End If
End Sub
Private Sub tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
Dim ID = DirectCast(sender.tag, Integer)
Dim curTimer = TimerList.Find(Function(x) x.Tag = ID)
curTimer.Stop()
Select Case ID
'change something on the UI to indicate that event x timer has elapsed
End Select
End Sub
End Class
答案 0 :(得分:1)
对此可能更好的解决方案是完全删除DispatcherTimer并使用普通线程执行此操作。
首先创建一个类来保存单个事件工作包 - 我添加了一种方法来传递延迟值,但如果它不符合您的需要,您可以省略它。这是一个简单的过程,它会让线程暂停延迟,然后引发一个新的事件让你捕获。如果您需要精确度,那么您可以使用秒表或其他方式实现延迟:
Public Class DelayThread
' Task information
Private _ID As Integer
Private _delay As Integer
Event onDelayUp(ByVal ID As Integer)
' Constructor
Public Sub New(ByVal myID As Integer, ByVal myDelay As Integer)
_ID = myID
_delay = myDelay
End Sub
Public Sub DelayProc()
System.Threading.Thread.Sleep(_delay)
RaiseEvent onDelayUp(_ID)
End Sub
End Class
现在您的设备将触发此处处理的事件:
Public Sub SomeEventFromExtDevice(ByVal ID As Integer) 'Handles ...
'get a "delay" value from somewhere, if you like
Dim newDelayTask As New DelayThread(ID, delay) 'added delay here
AddHandler newDelayTask.onDelayUp, AddressOf DoSomething
Dim t As New System.Threading.Thread( _
New System.Threading.ThreadStart(AddressOf newDelayTask.DelayProc))
t.Priority = Threading.ThreadPriority.Normal 'whatever priority
t.Start()
End Sub
这样,每次事件触发时,你都会启动一个等待延迟时间的新线程,DoSomething然后终止,在此过程中自行清理。
在这里你需要一些“DoSomething”程序:
'declare this somewhere
Delegate Sub dlgDoSomething(ByVal ID As Integer)
Public Sub DoSomething(ByVal ID As Integer) 'hooked to onDelayUp @ runtime above
'using "Me" here - if DoSomething is somewhere else
'you may need to refer to the main UI form instead
Me.Invoke(New dlgDoSomething(AddressOf uiDoSomething), New Object() {ID})
End Sub
将从每个线程调用DoSomething过程,因此必须在主UI线程上调用 - 然后需要:
Public Sub uiDoSomething(ByVal ID As Integer)
' Do Something with ID - UI thread is now executing this so you are safe
End Sub
如果知道事件的确切顺序很重要 - 知道它们到达的时间和顺序 - 那么你可以在SomeEventFromExtDevice中添加一个时间戳并传递它。
您可能还想添加一些关闭应用程序的处理 - 这里没有检查以确保线程在处理后不会尝试编组到主窗体上,例如。