質問者
非同期なイベントを同期させる?

質問
-
非同期なイベントのため、困っています。
イベントを同期させる方法や終了を待つ方法はありますか?
ご指導のほど、よろしくお願いします。
開発環境は VisualStudio2005 vb.net です。
以下のようなプログラムでクラスモジュールを呼び出しており、そのクラスモジュール内でイベントを発生させています。
正常にイベントが発生して終了するのですが、イベントが終了する前に戻り値がFalseで処理が終了してしまいます。
具体的な状況:クリックすると同時にメッセージボックスがFalseで表示され、その後にイベントが発生している(イベントは正常終了)
Public Class frmMainMenu
Private Sub btnComm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Comm.Click
Dim clsAAA As clsABC
Dim result As Boolean = clsAAA.AAARead("connect.txt")
MessageBox.Show(result.ToString)
End Sub
End Class
Public Class clsABCPublic WithEvents comAAA As Comm ' イベントの発生を定義
Public RtnValue As Boolean ' 戻り値Public Function AAARead(ByVal x As String) As Boolean
RtnValue = False
comAAA = New Comm
comAAA.Connect = xcomAAA.Excute = True ← これを実行することで以下のイベントが発生する
AAARead = RtnValue
End Function
Private Sub AAARead_Start(ByVal eventSender As Object, ByVal eventArgs As AAALib.CommEventArgs) Handles AAARead.Start
' エラーが返ってきたら、終了する
If eventArgs.result <> 0 Then
RtnValue = False
Exit Sub
End IfEnd Sub
Private Sub AAARead_End(ByVal eventSender As Object) Handles AAARead.End
' 正常終了の値を返す
RtnValue = TrueEnd Sub
End Class
- 編集済み 迷子の開発者 2009年11月19日 5:40
すべての返信
-
不可能ではないですが、とても勧められないので代案を。
Public Class Abc Public Event ReadCompleted(ByVal succeeded As Boolean) Public Sub StartRead(ByVal name As String) Dim com As New CommClient() AddHandler com.Start, AddressOf Me.com_Start AddHandler com.End, AddressOf Me.com_End com.Connect = name com.Execute = True End Sub Private Sub com_Start(ByVal sender as Object, ByVal e as CommEventArgs) If e.result <> 0 Then RaiseEvent ReadCompleted(False) End If End Sub Private Sub com_End(ByVal sender As Object) RaiseEvent ReadCompleted(True) End Sub End Class ' 利用側 Sub Hoge_Click(...) Handles Hoge.Clck Dim abc As New Abc() AddHandler abc.ReadCompleted, AddressOf Me.ShowComResult abc.StartRead("connect.txt") End Sub Private Sub ShowComResult(ByVal succeeded As Boolean) MessageBox.Show(secceeded.ToString()) End Sub
-
どうしても待ちたいのであればWaitHandleでブロックするとできますが、Commクラスが非同期で処理されているならHongliangさんの書いているようにしたほうが素直な処理だと思います。
Public Class clsABC Public WithEvents comAAA As Comm ' イベントの発生を定義 Public RtnValue As Boolean ' 戻り値 Private waitHandle As System.Threading.ManualResetEvent Public Function AAARead(ByVal x As String) As Boolean waitHandle = New System.Threading.ManualResetEvent(False) RtnValue = False comAAA = New CommClient() comAAA.Connect = x comAAA.Excute = True '← これを実行することで以下のイベントが発生する 'AAARead_Endが呼ばれて、waitHandleがシグナル状態になるまで待機する waitHandle.WaitOne() 'いらなくなったのでwaitHandleを処分 waitHandle.Close() waitHandle = Nothing AAARead = RtnValue End Function Private Sub AAARead_Start(ByVal eventSender As Object, ByVal eventArgs As AAALib.CommEventArgs) Handles AAARead.Start ' エラーが返ってきたら、終了する If eventArgs.result <> 0 Then RtnValue = False 'エラーだとAAARead_Endが呼ばれない場合は以下の処理をここに入れる 'If (waitHandle IsNot Nothing) Then ' '非同期処理が終わったのでAAAReadの処理を再開させる ' waitHandle.Set() 'End If Exit Sub End If End Sub Private Sub AAARead_End(ByVal eventSender As Object) Handles AAARead.End ' 正常終了の値を返す RtnValue = True If (waitHandle IsNot Nothing) Then '非同期処理が終わったのでAAAReadの処理を再開させる waitHandle.Set() End If End Sub End Class
-
Comm が GC に解放されてるんでしょうかね。
- Abc の com をローカル変数からメンバ変数に変更
- Form に ArrayList をローカル変数に配置、初期化
- Click イベントで作成した Abc オブジェクトを上記の ArrayList に Add
- ShowComResult メソッドで ArrayList から Remove(sender)
取り敢えず、ComStart メソッドや ComEnd メソッドに Debug.Print 文などを仕込んで、これらが呼び出されているかどうかを確認してみてください。 -