I need to do this all the time and don’t have the best memory in the world. Today, I decided that I looked this up one too many times so here’s my solution to this multithreading problem:
The Problem:
You try to modify UI components created in one thread in another thread. In VB, you can only make UI changes on the same thread that created it so you get a nice “Cross thread operation not valid” exception.
Here’s the wrong code:
thread = New System.Threading.Thread(AddressOf DoStuff) thread.Start()
Private Sub DoStuff() 'error occurs here' Me.Text = "Stuff" End Sub
The Solution:
If you’re super lazy or you’re very sure of what your code is going to do, you can simply disable the exception with:
Private Sub DoStuff() Me.CheckForIllegalCrossThreadCalls = False Me.Text = "Stuff" End Sub
This, of course, doesn’t prevent your code from making a mess. To do it properly, you need a delegate:
thread = New System.Threading.Thread(AddressOf DoStuff) thread.Start()
Private Delegate Sub DoStuffDelegate() Private Sub DoStuff() If Me.InvokeRequired Then Me.Invoke(New DoStuffDelegate(AddressOf DoStuff)) Else Me.Text = "Stuff" End If End Sub
Wildly simple right?
To understand what the code does, you need to understand what Invoke() does. It can be confusing to google Invoke() because Delegates and Controls have different implementations of Invoke(). In this case, we’re calling Invoke on a subclass of Control. That causes the method on the second thread which is going through DoStuff() to run a method on the first thread (which created the UI element).
Now if you need parameters, here’s another example where “ReallyLongProcess” is a subroutine that raises an event “Done” with a parameter “success”
AddHandler Me.Done, AddressOf WorkFinished thread = new System.Threading.Thread(AddressOf ReallyLongProcess) thread.Start()
Private Delegate Sub DoStuffDelegate(ByRef success as Boolean) Private Sub DoStuff(ByRef success as Boolean) If Me.InvokeRequired Then Me.Invoke(New DoStuffDelegate(AddressOf DoStuff), success) Else If success Then 'do stuff Else 'do stuff End If End If End Sub
Vb.net 2015 working sample:
Add button,add progressbar
Imports System.Threading Public Class Form1 Private trd As Thread Private Sub ThreadTask() Dim stp As Integer Dim newval As Integer Dim rnd As New Random() Me.CheckForIllegalCrossThreadCalls = False Do stp = ProgressBar1.Step * rnd.Next(-1, 2) newval = ProgressBar1.Value + stp If newval > ProgressBar1.Maximum Then newval = ProgressBar1.Maximum ElseIf newval < ProgressBar1.Minimum Then newval = ProgressBar1.Minimum End If ProgressBar1.Value = newval Thread.Sleep(100) Loop End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load trd = New Thread(AddressOf ThreadTask) trd.IsBackground = True trd.Start() End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MessageBox.Show("This is the main thread") End Sub End Class