私の質問が長すぎる場合は、事前にお詫び申し上げます。「別のクラスのスレッドによって受信されているメッセージで GUI のデータを更新する方法は?」という質問を見ました。それは私がやろうとしていることに非常に近いですが、答えは役立つほど詳細ではありませんでした.
VB6 アプリを VB.NET (VS2013) に変換しました。アプリの主な機能は、クエリを Linux サーバーに送信し、結果を呼び出しフォームに表示することです。WinSock コントロールはもう存在しないので、TcpClient クラスに関連付けられた関数を処理するクラスを作成しました。サーバーに正常に接続し、データを送受信できます。
問題は、このクラスを使用してクエリ メッセージをサーバーに送信するフォームが複数あることです。サーバーは、呼び出し元のフォームに表示されるデータで応答します。フォーム上のコントロールを更新しようとすると、「クロススレッド操作が無効です: コントロール x は、それが作成されたスレッド以外のスレッドからアクセスされました。」というエラーが表示されます。メイン/UI スレッドのコントロールを更新するために、Control.InvokeRequired を Control.Invoke と共に使用することになっていることはわかっていますが、VB で適切な完全な例を見つけることができません。また、各フォームにさまざまなコントロールを備えた 50 を超えるフォームがあります。各コントロールのデリゲート ハンドラーを作成したくありません。また、スレッドとデリゲートの概念は私にとって非常に新しいものです。過去 1 週間か 2 週間、このテーマについて見つけられるものはすべて読んでいますが、まだ立ち往生しています!
メインスレッドに戻す方法はありますか? そうでない場合、Control.Invoke を 1 回だけ使用して多数のコントロールをカバーする方法はありますか?
データの送受信を開始する前に、接続直後にスレッドを開始しようとしましたが、netStream.BeginRead は、コールバック関数が発火すると、独自のスレッドを開始します。また、BeginRead の代わりに Read を使用してみました。応答に大量のデータがある場合はうまく機能しませんでしたが、BeginRead の方がうまく処理できました。ドロシーがオズで立ち往生しているように感じます。メイン スレッドに戻りたいだけです。
ご協力いただきありがとうございます。
Option Explicit On
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Friend Class ATISTcpClient
Public Event Receive(ByVal data As String)
Private Shared WithEvents oRlogin As TcpClient
Private netStream As NetworkStream
Private BUFFER_SIZE As Integer = 8192
Private DataBuffer(BUFFER_SIZE) As Byte
Public Sub Connect()
Try
oRlogin = New Net.Sockets.TcpClient
Dim localIP As IPAddress = IPAddress.Parse(myIPAddress)
Dim localPrt As Int16 = myLocalPort
Dim ipLocalEndPoint As New IPEndPoint(localIP, localPrt)
oRlogin = New TcpClient(ipLocalEndPoint)
oRlogin.NoDelay = True
oRlogin.Connect(RemoteHost, RemotePort)
Catch e As ArgumentNullException
Debug.Print("ArgumentNullException: {0}", e)
Catch e As Net.Sockets.SocketException
Debug.Print("SocketException: {0}", e)
End Try
If oRlogin.Connected() Then
netStream = oRlogin.GetStream
If netStream.CanRead Then
netStream.BeginRead(DataBuffer, 0, BUFFER_SIZE, _
AddressOf DataArrival, DataBuffer)
End If
Send(vbNullChar)
Send(User & vbNullChar)
Send(User & vbNullChar)
Send(Term & vbNullChar)
End If
End Sub
Public Sub Send(newData As String)
On Error GoTo send_err
If netStream.CanWrite Then
Dim sendBytes As [Byte]() = Encoding.UTF8.GetBytes(newData)
netStream.Write(sendBytes, 0, sendBytes.Length)
End If
Exit Sub
send_err:
Debug.Print("Error in Send: " & Err.Number & " " & Err.Description)
End Sub
Private Sub DataArrival(ByVal dr As IAsyncResult)
'This is where it switches to a WorkerThread. It never switches back!
On Error GoTo dataArrival_err
Dim myReadBuffer(BUFFER_SIZE) As Byte
Dim myData As String = ""
Dim numberOfBytesRead As Integer = 0
numberOfBytesRead = netStream.EndRead(dr)
myReadBuffer = DataBuffer
myData = myData & Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead)
Do While netStream.DataAvailable
numberOfBytesRead = netStream.Read(myReadBuffer, 0, myReadBuffer.Length)
myData = myData & Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead)
Loop
'Send data back to calling form
RaiseEvent Receive(myData)
'Start reading again in case we don‘t have the entire response yet
If netStream.CanRead Then
netStream.BeginRead(DataBuffer, 0,BUFFER_SIZE,AddressOf DataArrival,DataBuffer)
End If
Exit Sub
dataArrival_err:
Debug.Print("Error in DataArrival: " & err.Number & err.Description)
End Sub