Trouble with Control.Invoke using VB.NET and CF3.5

1.5k views Asked by At

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?

2

There are 2 answers

2
Dennis Groome On BEST ANSWER

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
6
FloatingKiwi On

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