Click here to Skip to main content
15,920,508 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,
I am testing a background workder. I am running the following code for the test.
VB
Private Sub bgwTest_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwTest.DoWork
       Dim a As Integer = 0
       Do While a < 10 'Infinite loop
           ComboBox1.Items.Add(1)
       Loop
   End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       PictureBox1.Visible = True 'Contains my animated GIF
'Purpose is GIF keeps looping (it is animated GIF) despite computer is stuck in infinite loop
       bgwTest.RunWorkerAsync()
   End Sub





But this code generates the following error:

"Cross-thread operation not valid: Control 'ComboBox1' accessed from a thread other than the thread it was created on."

Please help.
Thanks
Furqan
Posted

Use a Delegate and InvokeRequired to add items to the ComboBox like this

VB
Delegate Sub SetComboCallBack(ByVal i As Integer)

VB
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim a As Integer = 0
        Do While a < 10 'Infinite loop
            UpdateComboBox(a)
            a += 1
        Loop

    End Sub
    Private Sub UpdateComboBox(ByVal i As Integer)
        If Me.ComboBox1.InvokeRequired Then
            Dim d As New SetComboCallBack(AddressOf UpdateComboBox)
            Me.Invoke(d, New Object() {i})
        Else
            Me.ComboBox1.Items.Add(i)
        End If
    End Sub


Hope this helps
 
Share this answer
 
Comments
Espen Harlinn 30-May-11 18:58pm    
Seems like the classic InvokeRequired/Invoke pattern, my 5
Wayne Gaylard 31-May-11 2:54am    
Thanks
The answers you already have are not 100% complete.
You cannot call anything related to UI from a non UI thread. You need to use either Invoke or BeginInvoke methods of System.Threading.Dispatcher (works with both Forms and WPF), or System.Windows.Forms.Control (Forms only).

Unlike Invoke, BegingInvoke returns immediately. Now, you may not use InvokeRequired if you're sure that invocation method is called always from a non-UI thread because InvokeRequired will always return true. It does not matter which control is used to call Invoke or BeginInvoke; it only should be the control participating in currently running Application.

Please see my past answers for detailed explanation on how it works and usage samples:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

—SA
 
Share this answer
 
Comments
Espen Harlinn 30-May-11 18:55pm    
Good points, my 5
Sergey Alexandrovich Kryukov 30-May-11 22:21pm    
Thank you, Espen.
--SA
 
Share this answer
 
You have to use a delegate to do it:

Updating the UI from a thread - The simplest way[^]
 
Share this answer
 
You cannot can access the UI controls in the DoWork event handler by creating a delegate and use the Control.Invoke method(here Me.Invoke) which is explained in Wayne's answer. You can also access them in the RunWorkerCompleted event as shown below.

I will create a field of type List<int> to store values of a in the DoWork like this:

VB
Private lst as List(Of Integer);
Private bgwTest as BackgroundWorker;
Public sub new()
{
 lst = new List(Of Integer);
 'Add the handlers
 AddHandler(bgwTest.DoWork, AddressOf(bgwTest_DoWork))
 AddHandler(bgwTest.RunWorkerCompleted, AddressOf(bgwTest_WorkCompleted))
} 


Private Sub bgwTest_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwTest.DoWork
       Dim a As Integer = 0
       Do While a < 10 'Infinite loop
           'ComboBox1.Items.Add(1)
           lst.Add(1);
       Loop
   End Sub

Private Sub bgwTest_WorkCompleted(sender as Object, e as RunWorkerCompletedEventArgs)
  'Now access your combobox and values in it using lst.
  For Each i as Integer in lst
     combobox1.Items.Add(i);
  End For
End Sub


Another way to do is explained in Wayne's answer by using delegates.

Hope it helped. :)
 
Share this answer
 
v2
Comments
Simon_Whale 30-May-11 9:18am    
you can do it in the do_work method, you need to test the controls invokerequired method and the use a delegate method as shown in solution 3
Tarun.K.S 30-May-11 9:33am    
Yes you are right. I think I will update my answer. Thanks for the pointer.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900