1

私は、外部デバイスによって生成された 5 つの個別のイベントに反応し、一定の遅延後に何かを行う必要があるプロジェクトに取り組んでいます。イベントは通常、一度に 1 つずつ発生しますが、同時に発生することもあります。これは悪い考えですか? もしそうなら、それはなぜですか?

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 
4

1 に答える 1

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 にタイムスタンプを追加して、それも渡すことができます。

アプリケーションをシャットダウンするための処理を追加することもできます。たとえば、メイン フォームが破棄された後に、スレッドがメイン フォームにマーシャリングしようとしていないことを確認するためのチェックはありません。

于 2012-01-06T16:30:58.603 に答える