Need help with INVOKE/DELEGATE

T

Terry Olsen

I'm running an asynchronous Socket. In the ReceiveCallback method, I need
to append what is received to a textbox on the main form. I have this code:

Private Sub ToChatWindow(ByVal msg As String)
txtChat.AppendText(msg)
End Sub

I've never used a delegate or invoke before and I'm rather confused on the
topic. Hope someone can help.

Thanks.
 
B

Bart Mermuys

Hi,

Terry Olsen said:
I'm running an asynchronous Socket. In the ReceiveCallback method, I need
to append what is received to a textbox on the main form. I have this
code:

Private Sub ToChatWindow(ByVal msg As String)
txtChat.AppendText(msg)
End Sub

I've never used a delegate or invoke before and I'm rather confused on the
topic. Hope someone can help.

1) You first define a delegate, to understand delegates better, you have to
know the compiler creates a class that can wrap a sub or function with the
same signature for each delegate you define. Like other classes a delegate
can be used as a variable and can be instantiated, the constructor takes a
sub or function that matches the delegate signature. BUT, in VB.NET
AddressOf returns an instantiated delegate, so you don't need to explicitly
use the delegate's constructor.

2) When ToChatWindow is called, we check if InvokeRequired is needed (eg.
when you call from an other thread) and if it is needed, then we call
txtChat.Invoke which will invoke ToChatWindow again (through a delegate
instance), but this time it runs on the UI thread and InvokeRequired will be
false.

Public Class SomeForm
Inherits Form

' define delegate ( signature matches ToChatWindow )
Private Delegate Sub ToChatWindowHandler( msg As String )

' delegate instance
Private ToChatWindowHandlerInst As ToChatWindowHandler

Public Sub New()
' create delegate instance
ToChatWindowHandlerInst = AddressOf ToChatWindow
End Sub

Public Sub ToChatWindow( msg As String )
If ( txtChat.InvokeRequired ) Then
txtChat.Invoke( ToChatWindowHandlerInst, _
New Object() { msg } )
Return ' dont forget
End If

' at this point you are in UI thread
txtChat.AppendText( msg )
End Sub

End Class


Don't want to confuse you, but notice that you can also call
SomeDelegateInstance.Invoke(<parameters>), but this will just invoke the
wrapped function without marshalling it to the UI thread unlike
Control.Invoke(SomeDelegateInstance, <parameters>) which does marshall to
the UI thread(which is the thread that created the Control).

And one more thing, there is Control.Invoke and Control.InvokeLater, the
former will wait until the function has run on the UI thread, the latter
will not wait until it is run and return immediately.

HTH,
Greetings
 
B

Bart Mermuys

Hi,

Terry Olsen said:
So the following code goes in Form1's NEW method?

Yes, that's the idea, you need an instantiated delegate so why not do it in
the form's constructor (Sub New), you could also use Form_Load, if you have
any problems with it or with the code explain where you think it goes wrong.

Usually a Form already has a New method, so it should look like:

Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()

' Add any initialization after the InitializeComponent() call.
ToChatWindowHandlerInst = AddressOf ToChatWindow
End Sub

HTH,
Greetings
 
T

Terry Olsen

Thanks for the help. I was able to simplify it and I came up with this,
which works great!

Delegate Sub ToChatWindowDelegate(ByVal msg As String)

Private Sub ToChatWindow(ByVal msg As String)
If txtChat.InvokeRequired Then
txtChat.Invoke(New ToChatWindowDelegate(AddressOf ToChatWindow), New
Object() {msg})
Else
txtChat.AppendText(msg)
End If
End Sub
 
B

Bart Mermuys

Hi,

Terry Olsen said:
Thanks for the help. I was able to simplify it and I came up with this,
which works great!

Delegate Sub ToChatWindowDelegate(ByVal msg As String)

Private Sub ToChatWindow(ByVal msg As String)
If txtChat.InvokeRequired Then
txtChat.Invoke(New ToChatWindowDelegate(AddressOf ToChatWindow), New
Object() {msg})
Else
txtChat.AppendText(msg)
End If
End Sub

That's ok too and i almost posted that, but then changed it, because
ToChatWindow could be called alot and each AddressOf creates a new
instantiated delegate, so to avoid re-creating the delegate each time, i
used a delegate field and created the delegate inside the ctor.

Greetings
 
B

Bart Mermuys

Hi,

Dennis said:
Thank-you for the excellent code..I learned a lot from it.

You're welcome, it is a commonly used pattern that i explained a bit.

Greetings
 
T

Terry Olsen

I see your point, but doesn't the delegate go away when the method it calls
exits?
 
B

Bart Mermuys

Hi,

Terry Olsen said:
I see your point, but doesn't the delegate go away when the method it calls
exits?

After Invoke there is no reference anymore, so it/they will be cleaned up
the next time GC runs, but that wasn't really the point.
It may be a personal thing, but i don't like the idea to create a new
delegate instance each time the function is called expecially when there is
an easy way to avoid it and the function is called repeatedly.
Performance-wise it may not differ that much.

Greetings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top