2011-07-15 18 views
4

Silverlight 5/Async CTPに関連するAsync CTPを使用するイベントを待っていますか?

レイアウトの更新を開始する非同期関数を作成し、レイアウトの更新が完了するまで待ちます。次のようなもの:

Private Async Function UpdateLayoutRoot() As Task 
     LayoutRoot.UpdateLayout() 
     Await LayoutRoot.LayoutUpdated <--- (NOT valid but shows desired outcome)   
    End Function 

どうすればいいですか?より一般的には、既存のイベントを待つためにAwaitをどのように使用できますか?

+0

これはおそらくReactive Extensions(RX)で最もよく行われるタイプのものです。 –

+0

あなたが私に尋ねるなら、更新されるべきレイアウトを待っているだけで、非常に面白い競争条件を求めているようです。それはうまくいったのですか? –

答えて

2

ありがとう! 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は結果(監視されているイベントに適切なイベント引数)を割り当て、非同期メソッドの残りのコードが実行されます。

3

これを達成する1つの方法は、イベント内で設定されているTaskCompletionSourceを待つことです。私はVB.NETを知らないのですが、うまくいけばC#から理解できます:

関連する問題