Can someone explain how to make callbacks in VB.NET?
Thank you
Printable View
Can someone explain how to make callbacks in VB.NET?
Thank you
In what context? Don't be afraid to elaborate. The character limit on a post is 10000 so you can give details.
sorry. I made two separate programs, one is the client and one is the server. both forms contain two text boxes. so when client is connected to the server, both programs can communicate with each other on the network. i received the following message when i tried to run the program, "Control control name accessed from a thread other than the thread it was created on." basically i have to use the thread-save calls, i looked at the MSDN help page, but i dont really understand what they did there.
Thanx
There are numerous examples of accessing controls from worker threads already posted on the forum, but it's a matter of know ing what to search for. Basically you have to create an instance of a delegate and invoke that on the UI to call a method. The delegate has to match the signature of the method that you want to call, which means the same number and type of arguments and the same return type. A delegate is basically an object that contains an instance of a method. Like other objects, that delegate can be passed around wherever you like. It can then be invoked anywhere, which executes method it contains, even though the method itself may not normally be accessible from that location. If you want to call a method that has no arguments and returns no value then you can use the existing MethodInvoker delegate:Now you can safely call that method from anywhere as is. The method itself will detect whether it is on a worker thread or not and do what's required. If it is on a worker thread then the delegate is created and passed to the the control's Invoke method. This carries the delegate across the thread boundary to the UI thread where the method it contains is executed. This means that if the SayHello method is executed on a worker thread it simply re-executes itself on the UI thread via the delegate. If you want to call a method that has arguments or returns something then you need declare your own delegate:VB Code:
Private Sub SayHello() If Me.Label1.InvokeRequired Then 'The method is being called on a worker thread so create a delegate that can cross the thread boundary. Me.Label1.Invoke(New MethodInvoker(AddressOf SayHello)) Else 'The method is being called on the UI thread so access the control directly. Me.Label1.Text = "Hello World" End If End SubVB Code:
Private Delegate Function GetTextDelegate() As String Private Function GetText() As String Dim result As String If Me.TextBox1.InvokeRequired Then 'We are on a worker thread. result = CStr(Me.TextBox1.Invoke(New GetTextDelegate(AddressOf GetText))) Else 'We are on the UI thread. result = Me.TextBox1.Text End If Return result End FunctionVB Code:
Private Delegate Sub SetTextDelegate(ByVal text As String) Private Sub SetText(ByVal text As String) If Me.TextBox1.InvokeRequired Then 'We are on a worker thread. Me.TextBox1.Invoke(New SetTextDelegate(AddressOf SetText), text) Else 'We are on the UI thread. Me.TextBox1.Text = text End If End Sub
A good article over asynchronous programming techniques can be found below for further explanation. There is a handy template at the end that might help make it easier to implement (if JM's post hasn't already done so :) )
http://www.aspfree.com/c/a/VB.NET/De...h-VB-NET-2005/
Thanx for the help guys, im reading all the resources now.
For more information you may also like to follow the Articles -> Advanced .NET link in my signature and read the Asynchronous Programming and Managed Threading sections.
Put your code in VBCODE tags at least.
VB Code:
'Server Imports System.Net.Sockets Imports System.Net Imports System.Windows.Forms Imports System.Threading Imports System.IO Public Class FrmServer Inherits Form Private connection As Socket 'Soccket object handles connection Private readThread As Thread 'server thread 'stream through which to transfer data Private socketStream As NetworkStream 'objects for writing and reading data Private writer As BinaryWriter Private reader As BinaryReader Public Sub New() MyBase.New() ' This call is required by the Windows Form Designer. InitializeComponent() 'txtDisplay.CheckForIllegalCrossThreadCalls = False ' txtInput.CheckForIllegalCrossThreadCalls = False ' Add any initialization after the InitializeComponent() call. readThread = New Thread(New ThreadStart(AddressOf RunServer)) readThread.Start() End Sub Private Sub FrmServer_Closing(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing System.Environment.Exit(System.Environment.ExitCode) End Sub Private Sub txtInput_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtInput.KeyDown Try If (e.KeyCode = Keys.Enter AndAlso Not connection Is Nothing) Then writer.Write("server>>" & txtInput.Text) txtDisplay.Text &= vbCrLf & "SERVER>>" & txtInput.Text If txtInput.Text = "TERMINATE" Then connection.Close() End If txtInput.Clear() End If Catch exception As SocketException txtDisplay.Text &= vbCrLf & "Error writing object" End Try End Sub 'allow client to connect and display text sent by user Public Sub RunServer() Dim listener As TcpListener Dim counter As Integer = 1 'Dim port As Int32 = 5000 ' Dim localAddr As IPAddress = IPAddress.Parse("localhost") 'wait for request, then establish connection Try listener = New TcpListener(5000) listener.Start() While True 'made changes here If Me.txtDisplay.InvokeRequired Then Me.txtDisplay.Invoke(New MethodInvoker(AddressOf RunServer)) Else txtDisplay.Text = "Waiting for connection" & vbCrLf End If connection = listener.AcceptSocket() socketStream = New NetworkStream(connection) writer = New BinaryWriter(socketStream) reader = New BinaryReader(socketStream) txtDisplay.Text &= "Connection " & counter & "received." & vbCrLf writer.Write("SERVER>>> Connection successful") txtInput.ReadOnly = False Dim theReply As String = "" Try Do theReply = reader.ReadString() txtDisplay.Text &= vbCrLf & theReply Loop While (theReply <> "CLIENT >>> TERMINATE" AndAlso connection.Connected) Catch inputOutputException As IOException MessageBox.Show("Client application closing") Finally txtDisplay.Text &= vbCrLf & "User terminated connection" txtInput.ReadOnly = True writer.Close() reader.Close() socketStream.Close() connection.Close() counter += 1 End Try End While Catch inputOutputException As IOException MessageBox.Show("Server applicatin closing") End Try End Sub End Class
VB Code:
'Client Side Imports System.Windows.Forms Imports System.Threading Imports System.Net Imports System.Net.Sockets Imports System.IO Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Private output As NetworkStream Private writer As BinaryWriter Private reader As BinaryReader Private message As String = "" Private readThread As Thread Public Sub New() MyBase.New() ' This call is required by the Windows Form Designer. InitializeComponent() 'txtDisplay.CheckForIllegalCrossThreadCalls = False 'txtInput.CheckForIllegalCrossThreadCalls = False ' Add any initialization after the InitializeComponent() call. readThread = New Thread(AddressOf RunClient) readThread.Start() End Sub Private Sub Form1_Closing(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing System.Environment.Exit(System.Environment.ExitCode) End Sub Private Sub txtInput_Keydown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtInput.KeyDown Try If e.KeyCode = Keys.Enter Then writer.Write("CLIENT>>> " & txtInput.Text) txtDisplay.Text &= vbCrLf & "CLIENT>>> " & txtInput.Text txtInput.Clear() End If Catch exception As SocketException txtDisplay.Text &= vbCrLf & " error writing object" End Try End Sub Public Sub RunClient() Dim client As TcpClient Try txtDisplay.Text &= "Attempting connection" & vbCrLf client = New TcpClient() client.Connect("127.0.0.1", 5000) output = client.GetStream() writer = New BinaryWriter(output) reader = New BinaryReader(output) txtDisplay.Text &= vbCrLf & "Got I/O streams" & vbCrLf txtInput.ReadOnly = False Try Do message = reader.ReadString txtDisplay.Text &= vbCrLf & message Loop While message <> "SERVER >>> TERMINATE" Catch inputOutputException As IOException MessageBox.Show("Client application closing") Finally txtDisplay.Text &= vbCrLf & "Closing connection.' & vbCrLf" writer.Close() reader.Close() output.Close() client.Close() End Try Application.Exit() Catch inputOutputException As Exception MessageBox.Show("Client application closing") End Try End Sub End Class
Alternatively you could have just editied your existing posts.
I don't see where you've tried at all. The example code I posted even sets the Text of a TextBox, so if that's all you're trying to do then you've already got the code.
sorry, forgot to put changes into server side, please have a look now.
im getting an error saying that "only one usage of each socket address is normally permitted"
Thanks
You don't invoke RunServer because that will just try to run EVERYTHING again. You write a method just like my SetText method (or in your case AppendText might be better) and you call that. It will create the delegate if required.
I made the method AppendText
VB Code:
private Delegate Sub AppendTextDelegate(ByVal text As String) Private Sub ApendText(ByVal text As String) If Me.txtDisplay.InvokeRequired Then Me.txtDisplay.Invoke(New AppendTextDelegate(AddressOf ApendText), text) Else Me.txtDisplay.Text = text End If End Sub
i actually tried this before your post, then where do i call this in the while loop. i know the error is at
txtDisplay.Text = "Waiting for conenction" & vbCrLf
sorry about this, im new to VB.NET
Firstly, you've changed the name of the method but not the implementation. That method is setting the Text, not appending it. If you want to be able to set or append text then you need two methods. You can use the same delegate for both though, because they have the same signature.
Secondly, you've got the method there so call it. Wherever you want to append text to the TextBox you call that method.
man, i understand 60% of wat you saying here. yes the implementation is wrong, since txtDisplay displays whatever is in the textbox. and i still fail to apply this whole thing. Could you please show me how to do it man? cheers
some coding will be much more appreciate, then i'll undertand by relate your code back to my work. better to learn and understand, also saves time. cheers
You already have the SetText method. If you want an AppendText method then instead of setting the Text:you append it:VB Code:
myTextBox.Text = textor better:VB Code:
myTextBox.Text &= textNow, wherever in your code you are currently setting the Text of the TextBox directly you call the SetText method instead. Likewise, wherever you are currently appending to the TextBox directly you call the AppendText method instead.VB Code:
myTextBox.AppendText(text)
so basically you saying that
VB Code:
Private Delegate Sub AppendTextDelegate(ByVal text As String) Private Sub AppendText(ByVal text As String) If Me.txtDisplay.InvokeRequired Then Me.txtDisplay.Invoke(New AppendTextDelegate(AddressOf AppendText)) Else Me.txtDisplay.AppendText(text) End If End Sub
and then instead of using
VB Code:
txtDisplay.Text = "waiting for connection" & vbCrLf
i should start using this new method AppendText
???VB Code:
txtDisplay.AppendText("Waiting for connection" & vbCrLf)
Thanks for your help
This:is not appending. It is setting. If you need to be able to set the text or append to the text then you need both a SetText method and an AppendText method. Other than that you're exactly right. You just need to follow these steps:VB Code:
txtDisplay.Text = "waiting for connection" & vbCrLf
1. Declare the delegate exactly as I have in post #4.
2. Declare and implement the SetText exactly as I have in post #4. If your TextBox is not named TextBox1 then change that appropriately.
3. Declare and implement the AppendText method the same way as SetText, but make that one change as I did in post #18 and you did in post #19.
4. Go through your code and everywhere that you're setting the Text of the TextBox directly you call your SetText method instead. If you're using just "=" then you're setting.
5. Go through your code and everywhere that you're appending to the Text of the TextBox directly you call your AppendText method instead. If you're using "&=" then you're appending.
That's it.
... this still ongoing?
this is the end of the topic. its done....thanx jmcilhinney