I
modified this example to output to a textbox on a windows form. So
instead of Console.WriteLine I used Textbox1.AppendText. Unfortuantely
this won't work being that async sockets work in a seperate thread and
I get an exception stating the control "textbox1" cannot be accessed
from a thread other than the one it was created on.
How do I take the data from the receive event and move it to another object created on another thread

How to access objects from another thread...
jack katz
I'll post the code i use.
In my global vars:
Delegate Sub UpdateLogDelegate(ByVal toAdd As String, ByVal newLIne As Boolean, ByVal color As Color)
Dim updateLogDel As UpdateLogDelegate = New UpdateLogDelegate(AddressOf UpdateLog)
I have a function that traps all gui updates from another thread(it doesn't matter what control you call invoke on as long as it is on the main form):
Public Sub UpdateGuiFromThread(ByVal method As String, ByVal msg As String, _
ByVal boolValue As Boolean, ByVal color As Drawing.Color)
'if form is not currently in closing sequence, update the GUI
If inExit = False Then
Select Case method
Case "updateSendButtonDel"
Me.btn_asynch_upload.Invoke(updateSendButtonDel, boolValue)
Case "updateServerDel"
Me.txt_server_name.Invoke(updateServerDel, msg)
Case "updateLogDel"
Me.txt_log.Invoke(updateLogDel, msg, boolValue, color)
Case "updateFileDel"
Me.txt_server_name.Invoke(updateFileDel, msg)
Case "updateStatusDel"
Me.txt_server_name.Invoke(updateStatusDel, msg)
Case "refreshGuiDel"
Me.txt_server_name.Invoke(refreshGuiDel)
Case "updateProgressBarDel"
Me.txt_server_name.Invoke(updateProgressBarDel, CInt(msg))
Case "updateTrayIconDel"
Me.txt_server_name.Invoke(updateTrayIconDel, msg)
End Select
End If
End Sub
Then the updateLog function:
Private Sub UpdateLog(ByVal toAdd As String, ByVal newLine As Boolean, ByVal color As Drawing.Color)
Me.txt_log.SelectionColor = color
Me.txt_log.SelectedText = toAdd
'Me.txt_log.AppendText(toAdd)
If newLine = True Then
Me.txt_log.AppendText(Environment.NewLine)
End If
ScrollToBottom()
End Sub
Then the call from another thread:
UpdateGuiFromThread("updateLogDel", "Sending file " + fileToUpload.ToString, True, NormColor)
This is not the most elegant code but it works for me.
Good Luck,
Lushdog
Kartik Subramani
abhig
Interesting, i tried shaka's technique a few month's ago and it didn't work for me. I'll try it out again, it would cut down alot on that garbage i posted above :)
lushdog
mr.flx
Here's the code that I currently have:
Imports System
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets
Public Class Form1
Protected Delegate Sub mydelsub(ByVal msg As String)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim sock As System.Net.Sockets.Socket
sock = New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)
sock.Connect(New IPEndPoint(IPAddress.Parse("127.0.0.1"), 80))
Dim request As String = "GET / HTTP/1.1" + Environment.NewLine
request = request + "host: http://joelclipperton.us" + Environment.NewLine
request = request + "connection: close" + Environment.NewLine + Environment.NewLine
Dim buffer As Byte() = System.Text.Encoding.ASCII.GetBytes(request)
Dim state As AsyncState = New AsyncState
state.sock = sock
state.buffer = buffer
sock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, New AsyncCallback(AddressOf SendCallback), state)
End Sub
Public Sub ReceiveCallback(ByVal ar As IAsyncResult)
Dim del As mydelsub
del = New mydelsub(AddressOf printtobox)
Try
Dim state As AsyncState = CType(ar.AsyncState, AsyncState)
Dim count As Integer = state.sock.EndReceive(ar)
If (count > 0) Then
del.Invoke(System.Text.Encoding.ASCII.GetString(state.buffer, 0, count))
state.sock.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, New AsyncCallback(AddressOf ReceiveCallback), state)
Else
del.Invoke(Environment.NewLine + "DONE: Socket was closed by the remote peer")
End If
Catch ex As Exception
del = New mydelsub(AddressOf showerror)
del.Invoke(ex.ToString)
End Try
End Sub
Public Sub SendCallback(ByVal ar As IAsyncResult)
Dim del As mydelsub
del = New mydelsub(AddressOf printtobox)
Try
Dim state As AsyncState = CType(ar.AsyncState, AsyncState)
state.sock.EndSend(ar)
del.Invoke("Data Sent...")
del.Invoke("Waiting to receive data")
del.Invoke("")
state.sock.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, New AsyncCallback(AddressOf ReceiveCallback), state)
Catch ex As Exception
del = New mydelsub(AddressOf showerror)
del.Invoke(ex.ToString)
End Try
End Sub
Protected Sub showerror(ByVal msg As String)
MessageBox.Show(msg)
End Sub
Protected Sub printtobox(ByVal msg As String)
Textbox1.AppendText(msg)
End Sub
End Class
Public Class AsyncState
Public sock As Socket
Public buffer As Byte()
End Class
I know the code works because I can send the output of the receive buffer to a message box and it works just fine. Upon executing I get a System.InvalidOperationException: Corsss-thread operation not valid: Control 'Textbox1' accessed from a thread other than the thread it was created on.
So using a delegate I'm still getting the same error. Is there something wrong with how i've implemented delegates
al kerr
Mike Cating
I'd write the code out for you but my eyes are burning right now.
lushdog
SpiderX81
hi,
the short and best way is this to creat a delegate for a method that take string, and then creat a method that check if the invokerequired if its required it call the delegate and you reference this method in your code not the textbox, this code is not tested but you got the idea
Delegate Sub settxtconn(ByVal text As String)
Sub SetTxtConnStatus(ByVal txt As String)
If Me.txtConnStatus.InvokeRequired Then
Dim d As settxtconn = AddressOf SetTxtConnStatus
Me.Invoke(d, New Object() {txt})
Else
Me.txtConnStatus.Text = txt
End If
End Sub
hope this helps