Brian Mulcahy
Brian Mulcahy

Reputation: 1503

VB.NET Cross-threading operation not valid even though Invoke is used!

I've been reading around trying to find out why I'd be getting this exception to no avail. I hope someone has seen this before:

I'm using Visual Basic 2010.

Briefly, I have a "Settings Panel" form which takes a while to create (it contains a lot of labels and textboxes), so I create it in another thread.

After it's loaded, it can be viewed by clicking a button which changes the form's visibility to True. I use the following subroutine to handle invokes for my controls:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
        If Control.InvokeRequired Then
            Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
        Else
            Action(Control)
        End If
End Sub

Here's the relevant part of my main code (SettingsTable inherits TableLayoutPanel and HelperForm inherits Form):

Public Class ch4cp
Public RecipeTable As SettingsTable
Public WithEvents SettingsWindow As HelperForm

Private Sub ch4cp_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

PanelCreatorThread = New Threading.Thread(AddressOf CreateStartupPanels)
        PanelCreatorThread.Start()

End Sub

 Private Sub CreateStartupPanels()

        SettingsWindow = New HelperForm("Settings Panel")
        SettingsTable = New SettingsTable

            SettingsTable.Create()
            SettingsWindow.Controls.Add(SettingsTable)

End Sub

Private Sub ViewSettingsPanel_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ViewSettingsPanel.CheckedChanged

InvokeControl(SettingsWindow, Sub(x) x.Visible = ViewSettingsPanel.Checked)

End Sub

The SettingsTable.Create() method generates a bunch of Labels and TextBoxes based on the contents of the application settings and adds them to the SettingsTable.

When I click on the ViewSettingsPanel checkbox, I get a cross-thread violation error. Any ideas? I would really appreciate it.

Upvotes: 1

Views: 1433

Answers (2)

SSpoke
SSpoke

Reputation: 5836

Better way to this in VB.NET is to use a Extension it makes very nice looking code for cross-threading GUI Control Calls.

Just add this line of code to any Module you have.

<System.Runtime.CompilerServices.Extension()> _
Public Sub Invoke(ByVal control As Control, ByVal action As Action)
    If control.InvokeRequired Then
        control.Invoke(New MethodInvoker(Sub() action()), Nothing)
    Else
        action.Invoke()
    End If
End Sub

Now you can write Cross-Thread Control code that's only 1 line long for any control call.

Like this, lets say you want to clear a ComboBox and it's called from threads or without threads you can just use do this now

cboServerList.Invoke(Sub() cboServerList.Items.Clear())

Want to add something after you clear it?

cboServerList.Invoke(Sub() cboServerList.Items.Add("Hello World"))

Upvotes: 0

Brian Mulcahy
Brian Mulcahy

Reputation: 1503

I figured it out. In case anyone else might be running into a similar issue, here was the secret:

In the SettingsTable class, I have a MakeTable method which looks like this:

Private Sub MakeTable()
        Me.Visible = False
        Me.Controls.Clear()
        ... add some controls ...
        Me.Visible = True
End Sub

I did this so that the control wouldn't flicker if the table was remade while visible. I don't entirely understand why (from reading, I'm guessing it's something like the handles for the child controls weren't being created because they weren't shown after being created, so IsInvokeRequired evaluated to False when it should have been True). The fix was to do this:

Private Sub MakeTable()
        If Not IsNothing(Me.Parent) Then If Me.Parent.Visible Then Me.Visible = False
        Me.Controls.Clear()
        ... add some controls ...
        Me.Visible = True
End Sub

This way, the child controls are "shown" on the invisible SettingsWindow form and their handles are therefore created. Works just fine now!

Upvotes: 1

Related Questions