tags:

views:

45

answers:

2

Hi,

I am new to multi-threading in VB.NET and have come across a problem whereby I am wanting to append text to a text box on a form from a service thread running in the background.

The application I am developing is a client/server listener, I have been able to get the client and server PC's to talk with each other (confirmed through MsgBox), however I am now struggling to get the service thread on the server to append the text to the textbox, nothing vissible occurs.

I have a form named testDebug which calls a class (RemoteSupport), this class does all the handshake tasks and updates the textbox with the connection data.

Can anyone identify where I am going wrong and point me in the right direction?

The following is the code I have: The form has a textbox named txtOutput, the following is from the remoteSupport class

Dim outMessage As String = (encoder.GetString(message, 0, bytesRead))
 MsgBox(outMessage, MsgBoxStyle.Information, "MEssage Received")
  If outMessage IsNot Nothing Then
    If testDebug.InvokeRequired Then
        ' have the UI thread call this method for us
        testDebug.Invoke(New UpdateUIDelegate(AddressOf HandleClientComm), New Object() {outMessage})    '
    Else
       testDebug.txtOutput.AppendText(outMessage)
    End If

    'RaiseEvent MessageReceived(outMessage) // a previous attempt to use custom events
 End If

I am not sure if the invoke method is the ideal solution or if custom events are, I have spent some time on trying to get custom events to work, but these didnt work either.

 // In the RemoteSupport class
 Public Delegate Sub MessageReceivedHandler(ByVal message As String)
 Public Shared Event MessageReceived As MessageReceivedHandler

// Located throughout the RemoteSupport class where debug information is required.
RaiseEvent MessageReceived(outMessage)

// Located in the code-behind of the form
Private Sub Message_Received(ByVal message As String)
testDebugOutput(message) // this is a function I have created 
                         // to append the text to the text box
End Sub

The code supplied has been cut down so if there is anything else that you want to see or any questions please let me know.

Thanks for your assistance.

EDIT: I have uploaded the two VB files (form and class) to my site, I would appreciate it if someone could have a look at it to help me with identifying the problem with the UI not updating.

I have tried a few other things but nothing seems to be updating the UI once the worker thread has started.

Form: mulholland.it/testDebug.vb.txt Class: mulholland.it/remoteSupport.vb.txt

Thanks for your assistance.

Matt

A: 

The Delegate method is likely the way you want to go, but I don't see the declaration of the UpdateUIDelegate anywhere

I believe your code should look something like this (assuming you have a reference to the testdebug form local to your remotesupport class

Dim outMessage As String = (encoder.GetString(message, 0, bytesRead))
MsgBox(outMessage, MsgBoxStyle.Information, "MEssage Received")
If outMessage IsNot Nothing Then
    If testDebug.InvokeRequired Then
        ' have the UI thread call this method for us
        testDebug.Invoke(New MessageReceivedHandler(AddressOf Testdebug.Message_Received), New Object() {outMessage})   
    Else
        testDebug.txtOutput.AppendText(outMessage)
    End If
end if
drventure
Unfortunately this didnt work, it didnt error but the UI textbox didnt update.
Lima
Hmm, if you step through, does it actually call the delegate or not even get there?
drventure
No it doesnt get to the delegate line. I have put a message box to test invokerequired and it always returns false. I have uploaded two files to my webserver which is the class and the form code, if you would like to have a look at it to get a complete picture that would be great.
Lima
+3  A: 

I have a form named testDebug...

If testDebug.InvokeRequired Then

This is a classic trap in VB.NET programming. Set a breakpoint on the If statement. Notice how it returns False, even though you know that the code is running on another thread?

InvokeRequired is an instance property of a Form. But testDebug is a class name, not a reference to an instance of a form of type testDebug. That this is possible in VB.NET has gotten a lot of VB.NET programmer in deep trouble. It is an anachronism carried over from VB6. It completely false apart and blows up in your face when you do this in a thread. You'll get a new instance of the form, instead of the one that the user is looking at. One that isn't visible because its Show() was never called. And otherwise dead as a doornail since the thread isn't running a message loop.

I answered this question several times already, with the recommended fix. I'll just refer you to them rather than rehashing it here:

http://stackoverflow.com/questions/3790574/form-is-not-updating-after-custom-class-event-is-fired/3790667#3790667

http://stackoverflow.com/questions/3643106/accessing-controls-between-forms/3643322#3643322

Hans Passant
Your links assisted me, after re-thinking the approach I was taking I decided to put the second class within the first class and make use of Me.Control.Invoke, much easier and it works now. Thanks for your assistance.
Lima
Doh, Completely missed that. I've tripped myself up on this very thing before and just looked right past it here. Thanks for the reminder!
drventure