0

I want to expose a method to update a text box with messages as a status log. I would like to use the AppendText method but I'm experiencing a strange multi threading issue when using it. I'm able to append new messages by concatenation just fine. The issue presents it's self as the text box not being shown, and then the Cross Thread access error shows up when closing the form. Here are examples of what works and what does not:

Working but not like AppendText unless extra steps are taken which is the last resort:

Public Sub AddMessage2(ByVal newMessage As String)
    If TextBoxStatus.InvokeRequired Then
        TextBoxStatus.BeginInvoke(Sub() TextBoxStatus.Text = TextBoxStatus.Text & newMessage & ControlChars.CrLf)
    Else
        TextBoxStatus.Text = TextBoxStatus.Text & newMessage & ControlChars.CrLf
    End If
End Sub

What I would like to use but does not work:

Public Sub AddMessage(ByVal newMessage As String)
    If TextBoxStatus.InvokeRequired Then
        TextBoxStatus.BeginInvoke(Sub() TextBoxStatus.AppendText(newMessage))
    Else
        TextBoxStatus.AppendText(newMessage)
    End If
End Sub

Additional info and updates: First of all I apologize for likely not supplying enough info up front.

At least part of the issue seems to be instantiating the form and calling AddMessage(newMessage) before calling Show() because the following code works:

Public Sub AddMessage(ByVal newMessage As String)
    If Me.Created Then
        If TextBoxStatus.InvokeRequired Then
            TextBoxStatus.BeginInvoke(Sub() TextBoxStatus.AppendText(newMessage))
        Else
            TextBoxStatus.AppendText(newMessage)
        End If
    End If
End Sub

I can always do something like the following, but I would like to what's going on :)

Private backLog As String = ""
Public Sub AddMessage(ByVal newMessage As String)
    If Me.Created Then
        If TextBoxStatus.InvokeRequired Then
            TextBoxStatus.BeginInvoke(Sub() TextBoxStatus.AppendText(backLog & newMessage))
        Else
            TextBoxStatus.AppendText(backLog & newMessage)
        End If
        backLog = ""
    Else
        backLog &= newMessage
    End If
End Sub

Also I don't consider this to be very elegant... especially when I add log size limits

Jon
  • 1
  • 2
  • Under normal circumstances, your code should work. Are you starting the secondary thread that calls `AddMessage` in the form's `Sub New` or some other point such that `TextBoxStatus`'s handle has not yet been created? What happens in you add `If Not TextBoxStatus.IsHandleCreated Then Exit Sub` as the 1st statement in `AddMessage`? – TnTinMn Oct 13 '16 at 00:44
  • @TnTinMn The form hadn't been shown yet so I'm sure you're right. I wanted to create the form without showing it until the user opens it from a menu. I'm going to look for how I can do this, but if you know off the top of your head that would be great :) Thanks again – Jon Oct 13 '16 at 18:18
  • Did my suggestion above to exit if the handle is not created solve the cross-thread error? If so, I post a hack to buffer the text until the handle is created. It will not be pretty though. – TnTinMn Oct 13 '16 at 20:00
  • Assigning the Text property is subtly different from using AppendText(). A control like RTB always has a valid Text property but AppendText() can only work when the control was created and its IsHandleCreated property is True. This is otherwise a very simple order-of-execution problem, your code is calling AddMessage() before the UI is created. Well, can't work, the RTB doesn't exist yet. Use the debugger's Call Stack window to see how that happened. – Hans Passant Oct 13 '16 at 21:50
  • Thanks all, I ended up using this answer to allocate a handle for the form before any other threads attempt to access it: http://stackoverflow.com/a/4411493/2415598 – Jon Oct 14 '16 at 21:43

1 Answers1

0

I would suggest this:

Public Sub AddMessage(ByVal newMessage As String)
    If TextBoxStatus.InvokeRequired Then
        TextBoxStatus.BeginInvoke(New Action(Of String)(AddressOf AddMessage), newMessage)
    Else
        TextBoxStatus.AppendText(newMessage)
    End If
End Sub
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46