0

THis is my first time using threading for an application. I'm working with VB.NET, VS2008, and CF3.5

I made a small test project to try to understand how Threading works, especially when trying to access UI Controls in another thread. My Form is just a single button that says "Start" and should toggle back and forth with "Stop" when pressed.

Here's the code for my test project that I've put together looking at several examples I've found online.

Public Class Form1

Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
    Dim myThread As New System.Threading.Thread(AddressOf ChangeText)
    myThread.Start()
End Sub

Private Sub ChangeText() 
    If button1.InvokeRequired Then
        Me.Invoke(New Threading.WaitCallback(AddressOf ChangeText))
    Else
        If button1.Text = "Start" Then button1.Text = "Stop"
        If button1.Text = "Stop" Then button1.Text = "Start"
    End If
End Sub

It builds and deploys just fine but as soon as I click the Button I get an "ArgumentException is unhandled" on the Invoke.

What am I doing wrong?

  • You'll have to make up your mind whether or not ChangeText is going to take that *obj* argument. If it does, as necessary to keep Thread happy, then Invoke() is going to require an extra argument. Nothing will do. – Hans Passant Aug 16 '16 at 16:11

2 Answers2

0

I've rewritten the Invoke to just call the sub routine using a lambda. Also I changed from Invoke to BeginInvoke as you don't need to wait for it to complete.

Public Class Form1

    Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
        Dim myThread As New System.Threading.Thread(AddressOf ChangeText)
        myThread.Start()
    End Sub

    Private Sub ChangeText()
        If button1.InvokeRequired Then
            Me.BeginInvoke(Sub() ChangeText())
        Else
            If button1.Text = "Start" Then button1.Text = "Stop"
            If button1.Text = "Stop" Then button1.Text = "Start"
        End If
    End Sub

End Class

[Edit]

I've amended the code to use delegates instead of lamdbas.

Public Class Form1

        Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
                Dim myThread As New System.Threading.Thread(AddressOf ChangeText)
                myThread.Start()
        End Sub

        Private Sub ChangeText()
                If button1.InvokeRequired Then
                        Me.BeginInvoke(New Threading.ThreadStart(AddressOf ChangeText)))
                Else
                        If button1.Text = "Start" Then button1.Text = "Stop"
                        If button1.Text = "Stop" Then button1.Text = "Start"
                End If
        End Sub

End Class   
FloatingKiwi
  • 4,408
  • 1
  • 17
  • 41
  • I tried using the BeginInvoke line from your code but VS2008 immediately underlined Sub and says "Expression expected." – Dennis Groome Aug 16 '16 at 16:20
  • Seems to be 2008 specific. http://stackoverflow.com/questions/2786753/vb-net-action-delegate-problem – FloatingKiwi Aug 16 '16 at 16:26
  • Adding the state as Object argument solved the error in VS2008 for the Invoke, but now I have an error trying to call that sub as a thread. How do I pass an argument to a thread? – Dennis Groome Aug 16 '16 at 16:30
  • I'm getting an error in VS2008 on the `Dim myThread As New System.Threading.Thread(AddressOf ChangeText)' line teling me "Method 'Private Sub ChangeText(state as Object)' does not have a signature compatible with delegate 'Delegate sub ThreadStart()" – Dennis Groome Aug 16 '16 at 16:34
  • Odd. It should be using ParameterizedThreadStart instead of TheadStart. Unfortunately I have to go now. Running late .... – FloatingKiwi Aug 16 '16 at 16:39
  • For the record, lambda expressions doesn't exist in .NET 3.5. – Visual Vincent Aug 16 '16 at 19:51
-2

Here's the code that finally worked:

Public Class Form1

Delegate Sub TextDelegte()
Private myTextSub As TextDelegte = New TextDelegte(AddressOf ChangeText)

Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click

    Dim myThread As New System.Threading.Thread(AddressOf ChangeText)
    myThread.Start()
End Sub

Private Sub ChangeText()
    If button1.InvokeRequired Then
        Invoke(myTextSub)
        System.Threading.Thread.Sleep(100)
    Else
        If button1.Text = "Start" Then
            button1.Text = "Stop"
        ElseIf button1.Text = "Stop" Then
            button1.Text = "Start"
        End If
    End If
End Sub

End Class
  • The delegate you have declared here is the same as the ThreadStart delegate so you can just use that. Why do you need the Sleep call? – FloatingKiwi Aug 17 '16 at 01:56
  • Good catch, the Sleep shouldn't be there, that's an artifact from testing when trying to figure out a strange behavior on the embedded system this is running on. – Dennis Groome Aug 17 '16 at 10:56