Question Control 'txtMessages' accessed from a thread other than the thread it was created on.

kdxrider

New member
Joined
Jan 4, 2009
Messages
1
Programming Experience
1-3
I have a System.ComponentModel.BackgroundWorker component (BackGroundClientWait) within a class(myClass) that raises an event (message). My class is declared on a form (myForm) which contains a textbox (txtMessages). When I handle the event (message) and write the passed value (ByVal value as string) to the txtMessages textbox I get "Cross-thread operation not valid: Control 'txtMessages' accessed from a thread other than the thread it was created on.". I don't understand why this is happening because I am not accessing the txtMessages from another thread, just responding to an event from another thread. Any idea? Thanks in advance.

Public Class clsMyClasss

Dim WithEvents BackGroundClientWait As System.ComponentModel.BackgroundWorker = New System.ComponentModel.BackgroundWorker

Private Sub BackGroundClientWait_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackGroundClientWait.DoWork

RaiseEvent Message("Client: Received " & myString.Trim)

End Sub

End Class


Private Sub myClass_Message(ByVal value As String) Handles myClass.Message
txtMessages.Text = txtMessages.Text & value & vbCrLf
End Sub


System.InvalidOperationException
{"Cross-thread operation not valid: Control 'txtMessages' accessed from a thread other than the thread it was created on."}
 
DoWork is another thread. Use the ProgressChanged or RunWorkerCompleted events to access UI thread, or use the common threading technique Control.Invoke to invoke a method by delegate on the control thread.
 
Tip: Events don't really have special threads devoted to handling them.. and an event is a bit of a skin for a construct called a delegate. Delegates are reasonably simple to understand, if you think of them as a way of attaching an object reference to a method (sub/function). You can pass the delegate around like a normal object and cause the method to run every time you opush the "Invoke" button

Events are no different, and typically we think of events in terms of their handlers. Textbox.TextChanged is an event. It's actually just an empty placeholder. When you attach a handler to it, it receives a delegate.. i.e. it has an object reference to a method attached to it. Youre telling the framework what method you'd like called when the text is changed.
It is done this way so that the method can be called anything you like.

Now, when it comes to raising an event yourself, remembr, all youre doing is invoking a method by object rerence rather than typing the name into your owncode, thus is executson the thread that the call comes from.

In code, basically, there is no difference between:

VB.NET:
Sub MySub()
  blah
End Sub

...

'there is no difference between this:

Dim myDeleg a New ThreadStart(AddressOf MySub)
myDeleg.Invoke()

'and this:

MySub()

The currently executing thread will jump into MySub and process the code there. Note, I picked a ThreadStart delegate because it's a parameterless return-less delegate suitable for a Sub. It has nothing to do with new threads or multithreading


BackgroundWorker has the ability to manage your ui crossthreading for you, but you have to set WorkerReportsProgress to True, and then handle the ProgressChanged event. Use the int progresspercentage or the object userState for communication of values to be displayed etc

In DoWork() call ReportProgress, and the BGW will activate the thread that created it to call whatever handler you have attached to the ProgressChanged event
DoWork() is run by a different thread. Do not manipulate UI controls from it directly
 
Back
Top