2

別のクラスのスレッドによって受信されているメッセージで GUI のデータを更新する方法は?

サーバーからデータを受信するスレッドを持つクラスがあります。このスレッドは、サーバーからメッセージを受け取るたびにイベントを発生させます。このイベントはスターター クラス (GUI を含むメイン クラス) 内で処理されます。イベントハンドラー(たとえばDisplayData() 、他のクラスが受信したメッセージを表示する必要があります。私のコードは次のようになります

Class GUI
    receiverObj = New Receiver()
    Addhandler receiverObj.MessageAlert, Addressof DisplayData
    ...
    ...
    Sub DisplayData()
        Dim str As receiverObj.ReceiveData

        lbEvents.Add.Items(str)   ' lbEvents is a ListBox inside the GUI that displays messages from Receiver 
    End Sub
End Class


Class Receiver

    Public Event MessageAlert()
    Sub New ()
        MyTcpClient = New TcpClient(hostIP, port)               
        MyTcpClient.GetStream.BeginRead(ReceiveData, 0, PacketSize, AddressOf ReceiveStream, Nothing)
    End Sub

    Public Sub ReceiveStream(ByVal ar As IAsyncResult)
        Dim ByteCount As Integer

        Try
            ByteCount = MyTcpClient.GetStream.EndRead(ar)
            Dim t As New Threading.Thread(Sub() RaiseEvent MessageAlert())
            MyTcpClient.GetStream.BeginRead(ReceiveData, 0, PacketSize, AddressOf ReceiveStream, Nothing)
     End Sub
End Class

ウィンドウがクラッシュまたはハングし、リストボックスにデータが表示されません。言って例外をスローします

クロススレッド操作が無効です: コントロール xxx は、それが作成されたスレッド以外のスレッドからアクセスされました。

誰でもこのエラーを修正する方法を提案できますか? 別のクラスのスレッドによって受信されているメッセージで GUI のデータを更新する方法は?

4

1 に答える 1

5

Windows アプリケーションの GUI 要素の更新は、GUI を作成したスレッドで行う必要があります。

これを修正するために、制御が GUI スレッドに渡され、試行中の更新を実行できるデリゲートを起動できる Invoke というメソッドがあります。

これを機能させるには、いくつかのことが必要です。

  1. デリゲートタイプなど

    Delegate Sub MyGUIUpdateDelegate()
  2. デリゲートの型の変数

    Public myGUIUpdateDelegate as MyGUIUpdateDelegate
  3. デリゲートに一致し、機能するシグネチャを持つメソッド:

    Public Sub MyGuiEventHandler()
    ' Do work on proper GUI thread, via Control.Invoke, ' such as listbox population
    If (Me.InvokeRequired) Then Me.Invoke( myGUIUpdateDelegate) Else // do control specific work, we're on the GUI thread here End If

    End Sub

  4. デリゲートへのイベント ハンドラーの割り当て:

    myGUIUpdateDelegate = New MyGuiUpdateDelegate(AddressOf myForm.MyGuiEventHandler)
  5. イベント スレッドから適切なスレッドへの Control.Invoke を介して updater メソッドを呼び出します (フォーム インスタンス変数の名前が myForm であると仮定します)。

    myForm.Invoke(myForm.myGUIUpdateDelegate);

これは少なくとも、始めるのに役立つフレームワークです。アイデアは、更新を誘発したいバックグラウンド スレッドが直接 GUI 更新を行うべきではない (実際にはできない) ということです。GUI スレッドへのコンテキスト スイッチを開始する適切な方法は、Invoke メソッドを呼び出して、適切な GUI スレッドで GUI アップデーターを呼び出すことです。

さらに、デリゲートにパラメーターを渡す必要がある場合は、定義するデリゲートのシグネチャを変更してパラメーターを含め、Invoke メソッドを変更してハンドラーで引数を提供し、2 番目の引数を Invoke に渡します。

お役に立てれば。

于 2012-09-19T22:34:20.833 に答える