ありがとう! TaskCompletionSourceを使用するあなたの提案は、私が必要としたものです。私はTaskCompletionSourceとLucian Wischik's Async CTP specificationを組み合わせて、CLRまたはルーティングイベントを待つために使用できる汎用Silverlight 5クラスのペアを開発しました。非同期CTP(AsyncCtpLibrary_Silverlight)だけが必要です(恐ろしいRxライブラリは必要ありません)。
Public Class AwaitableEvent(Of TResult)
Private eta As EventTaskAwaiter(Of TResult) = Nothing
Sub New(ByVal Sender As Object, ByVal EventName As String)
eta = New EventTaskAwaiter(Of TResult)
Dim ei as EventInfo = Sender.GetType.GetEvent(EventName)
Dim d = [Delegate].CreateDelegate(ei.EventHandlerType,
Me, "EventCompletedHandler", True, True)
ei.AddEventHandler(Sender, d)
End Sub
Public Function GetAwaiter() As EventTaskAwaiter(Of TResult)
Return eta
End Function
Private Sub EventCompletedHandler(ByVal sender As Object, ByVal e As TResult)
eta.tcs.TrySetResult(e)
End Sub
End Class
Public Class EventTaskAwaiter(Of TResult)
Friend tcs As New TaskCompletionSource(Of TResult)
Public ReadOnly Property IsCompleted As Boolean
Get
Return tcs.Task.IsCompleted
End Get
End Property
Sub OnCompleted(r As Action)
Dim sc = SynchronizationContext.Current
If sc Is Nothing Then
tcs.Task.ContinueWith(Sub() r())
Else
tcs.Task.ContinueWith(Sub() sc.Post(Sub() r(), Nothing))
End If
End Sub
Function GetResult() As TResult
If tcs.Task.IsCanceled Then Throw New TaskCanceledException(tcs.Task)
If tcs.Task.IsFaulted Then Throw tcs.Task.Exception.InnerException
Return tcs.Task.Result
End Function
End Class
ここでは、AwaitableEventクラスを使用してマウスイベント、キーボードイベント、タイマーイベントを処理する例を示します。
Private Sub AECaller()
GetMouseButtonAsync()
MessageBox.Show("After Await mouse button event")
GetKeyAsync()
MessageBox.Show("After Await key event")
GetTimerAsync()
MessageBox.Show("After Await timer")
End Sub
Private Async Sub GetMouseButtonAsync()
Dim ae As New AwaitableEvent(Of MouseButtonEventArgs)(LayoutRoot, "MouseLeftButtonDown")
Dim e = Await ae
MessageBox.Show(String.Format("Clicked {0} at {1},{2}",
e.OriginalSource.ToString,
e.GetPosition(LayoutRoot).X,
e.GetPosition(LayoutRoot).Y))
End Sub
Private Async Sub GetKeyAsync()
Dim ae As New AwaitableEvent(Of KeyEventArgs)(LayoutRoot, "KeyDown")
Dim e = Await ae
MessageBox.Show(String.Format("Key {0} was pressed", e.Key.ToString))
End Sub
Private Async Sub GetTimerAsync()
Dim StopWatch As New DispatcherTimer
StopWatch.Interval = New TimeSpan(TimeSpan.TicksPerSecond * 6)
Dim ae As New AwaitableEvent(Of EventArgs)(StopWatch, "Tick")
StopWatch.Start()
Await ae
MessageBox.Show(String.Format("It's {0}seconds later!", StopWatch.Interval.TotalSeconds))
StopWatch.Stop()
End Sub
期待どおり、Await文は、呼び出し元関数に直ちに制御を返します。後でイベントが完了すると、Awaitは結果(監視されているイベントに適切なイベント引数)を割り当て、非同期メソッドの残りのコードが実行されます。
これはおそらくReactive Extensions(RX)で最もよく行われるタイプのものです。 –
あなたが私に尋ねるなら、更新されるべきレイアウトを待っているだけで、非常に面白い競争条件を求めているようです。それはうまくいったのですか? –