KnowDotNet NetRefactor

Controls created on one thread cannot be parented to a control on a different thread

Filling a Datagrid from a Separate Thread

by Les Smith
Print this Article Discuss in Forums

Error: Controls created on one thread cannot be parented to a control on a different thread.  How do I fill a DataGrid on a form from a thread that did not create the control?

Normally, Windows Form or Control methods cannot be called from a thread that did not create the control.  Attempting this will result in an exception, "Error: Controls created on one thread cannot be parented to a control on a different thread."  

You can create a Form or Control on any thread.  However, having done this, you cannot call method of the form or control on a different thread.  This means that method calls that come from threads other that the one that created the form or control must be executed or marshalled on the creating thread.  The following code examples demonstrate how to get around the problem.

First, you must import the threading namespace.

Imports System.Threading

Next, in the declarations section, place some variables.  The first one is a MethodInvoker Delegate which will allow the separte thread to invoke a method on the form's thread.  The other three variables are to get the data from database.  I have placed them at the module (form) level so that the thread can access them.

   Dim CallDataGridBinder As New MethodInvoker(AddressOf DataGridBinder)
  
Dim dtMDA As DataTable
  
Dim dsMDA As DataSet
  
Dim dtName As String

Next, I created a method to do the actual data binding.  This method is called by the CallDataGridBinder Delegate shown above.

   Private Sub DataGridBinder()
      
Me.dgJobsLines.SetDataBinding(dsMDA, dtName)
  
End Sub

Finally, here is the code, running in an asynchronous thread to get the data from the database.  Once the data is retrieved, the Delegate, described previously, is invoked, using the form's BeginInvoke method.

   dsMDA = ws.JobAndLinesToday(DateTime.Today)
   dtMDA = dsMDA.Tables(0)
   dtName = dtMDA.TableName
  
Me.BeginInvoke(Me.CallDataGridBinder)

It seems a little out of the way, but when you start using Threads, you are moving into a different level of programming.  Problems that you never had in a single-thread environment will appear.  They are not unsolvable, but they can get complex.

Additional help on this subject is available at Microsoft.

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing