Cross-thread Exception with UserControl Initialized from BackGroundWorker

I have a Windows Form with 3 variables declared as my own User Controls, a BackGroundWorker, 1 panel and 3 buttons

Dim uc1 As DocumentTab

Dim uc2 As HomeScreen

Dim uc3 As StylePage

These User controls are initialized from the BackGroundWorker.DoWork().

uc1 = New DocumentTab

uc2 = New HomeScreen

uc3 = New StylePage

The Click Events of the buttons calls this method to add the specified user control to the panel. Keep in mind that this method is always executed from the UI Thread.

Private Sub AddControlToTab(ByVal cCTL As Control, ByVal Panel As Control)

Panel.SuspendLayout()

Panel.Controls.Clear()

With cCTL

.BackColor = System.Drawing.Color.Transparent

.Dock = System.Windows.Forms.DockStyle.Fill

.Location = New System.Drawing.Point(0, 0)

.TabIndex = 0

End With

Panel.Controls.Add(cCTL)

Panel.ResumeLayout()

End Sub

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

I only get the Cross-Thread error when adding uc1 which is of type DocumentTab.

Is it possible or even good practice to do what I'm doing (Initialize User Controls from a Thread other than the UI)

By the way this form is only a test since the real form will have 30+ UserControls and Initializing all of them could take a few seconds and thus my need to do it from a seperate thread to keep the UI responsive.



Answer this question

Cross-thread Exception with UserControl Initialized from BackGroundWorker

  • hanagomi

    I've modified the AddControlToTab method to be thread safe. However the line in yellow always returns False although the control was initialized from the Worker thread while this method is always ran on the UI thread. Do I need to implement some Interface in my UserControl so that InvokeRequired returns the proper value

    Private Sub AddControlToTab(ByVal cCTL As Control, ByVal Panel As Control)

    If cCTL.InvokeRequired Then

    Dim d As New AddControlCallback(AddressOf AddControlToTab)

    Me.Invoke(d, New Object() {cCTL, Panel})

    Else

    Panel.SuspendLayout()

    Panel.Controls.Clear()

    With cCTL

    .BackColor = System.Drawing.Color.Transparent

    .Dock = System.Windows.Forms.DockStyle.Fill

    .Location = New System.Drawing.Point(0, 0)

    .TabIndex = 0

    End With

    Panel.Controls.Add(cCTL)

    Panel.ResumeLayout()

    End If

    End Sub


  • AndyMcBal

    It's because you created the controls in the DoWork event, which is on a different thread than the UI. Generally, you should create the controls in the initializer or form_load event, and do your data access in the DoWork event; binding the controls in the Completed event.

    You don’t really need to worry about a large number of controls slowing your down your form. As an experiment, create an empty form and add a few thousand textboxes, then run it. You'll see the form gets created pretty quickly. Most forms delays are caused when one tries to retrieve data from the database on the same thread as the UI.


  • Matthijs Koopman

    So would it be safe to say that it is NOT possible to Initialize/Create UserControls from a thread other than the UI thread
  • winprock

    well not exactly. you cannot access a control from another thread which it did not create, it should go to the original thread that created that control.

    To access it, you need to invoke it. Here is an example without using the background worker

    http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=689966&SiteID=1

    backgroundworker example:

    http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx



  • HMote

    I continue to get the Cross-Threaded exception.

    Let me try to explain better since I think you may have gotten confused by last post...

    The method AddControlToTab is ALWAYS executed on the UI Thread. Therefore the line

    If cCTL.InvokeRequired Then

    should ALAWAYS return TRUE because the User Control cCTL is ALWAYS initialized/created from the Worker thread.


  • Ravie14

    no thats fine. If it works then thats good as long as you dont get the cross threading exception. if the control was initialized in the worker thread and you are doing the invoking on the worker thread then it will return false. If however you were accessing it on a different thread then it will require invoking

  • Cross-thread Exception with UserControl Initialized from BackGroundWorker