• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 527
  • Last Modified:

VB.NET Thread issue

When a thread I started finishes, I raises an event back to the main process that the thread has completed.  One of the things I want to do in this call back is add an entry to a list box on the main form, but when the event happens I get this error:

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

How can I add an entry to this list box from the finishing thread?


0
onemorecoke
Asked:
onemorecoke
  • 6
  • 5
  • 5
  • +1
2 Solutions
 
nepaluzCommented:
Have you implemented your custom threading or utilised the "out of the box" threading of background worker? I'd use the latter and simply add the call to UI in the process changed event.
0
 
onemorecokeAuthor Commented:
Here is the code involved:

=========================
Up top in the main form:

Dim t As clsThreadWritebackBatch
Dim ThreadBatch As System.Threading.Thread


=========================
The button click that creates the thread:

If ThreadBatch Is Nothing Then
                Dim t As New clsThreadWritebackBatch
                Dim ThreadBatch As New System.Threading.Thread(AddressOf t.ProcessBatch)
                AddHandler t.FinishedBatch, AddressOf FinishedBatchEventHandler
                ThreadBatch.Priority = System.Threading.ThreadPriority.BelowNormal
                ThreadBatch.Start()
End If

=========================
The callback function

Public Sub FinishedBatchEventHandler(ByVal ItemCount As Long)
...
lbStatus.Items.Add(FormatDateTime(Now, DateFormat.GeneralDate) & " - Finished")
...
end sub


0
 
Mohamed AbowardaSoftware EngineerCommented:
The exception is occurring because you are calling the method FinishedBatchEventHandler() from another thread other than the main one that it was created on.

You need to use delegate to call FinishedBatchEventHandler from the main thread.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
nepaluzCommented:
It may be worth your while to run your rule over the following walk-through in implementing the backgroundworker as a class (out of the box threading).

http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx
0
 
Mohamed AbowardaSoftware EngineerCommented:
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I agree that the BackgroundWorker() is much easier.

Here's how to do it the manual way though:
Public Delegate Sub FinishedDelegate(ByVal ItemCount As Long)

Public Sub FinishedBatchEventHandler(ByVal ItemCount As Long)
    If Me.InvokeRequired Then
        Me.Invoke(New FinishedDelegate(AddressOf FinishedBatchEventHandler), New Object() {ItemCount})
    Else
        ' *** it's safe to update any GUI elements in this 'Else' block ***
        ...
        lbStatus.Items.Add(FormatDateTime(Now, DateFormat.GeneralDate) & " - Finished")
        ...
    End If
End Sub

Open in new window

0
 
onemorecokeAuthor Commented:
When you say "manual way", does that mean that the backgroundworker component is doing the same thing I am doing manually or is it a completely different thing?  I am used to in-process and out-of-process terminology.  Is what I am doing out-of-process?

Thanks
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Using the BackgroundWorker() control you don't need to use Invoke()/Delegates since the ProgressChanged() and RunWorkerCompleted() events have already been marshaled to the main UI thread for you.  So when those events are received you can simply directly update your GUI without worrying about it.

...so "under the hood" the BackgroundWorker() control is doing this kind of thing for you.  There are situations where knowing how to do it manually are beneficial as well.
0
 
onemorecokeAuthor Commented:
Thanks Idle_Mind!  Would you be able to show me how I could accomplish this with the BackgroundWorker() control?
0
 
Mohamed AbowardaSoftware EngineerCommented:
"Cross-thread operation not valid" exception only occurs when you try to make changes on controls from another thread other than the one that it was created on.

After you add the BackgroundWorker to your form, call BackgroundWorker1.RunWorkerAsync() to start.

The BackgroundWorker support three main events:
1. DoWork:
It occur after you call RunWorkerAsync() method and it execute the code on another thread other than the main one.

2. ProgressChanged:
This event raise whenever you call ReportProgress() method and it execute the code on the main thread (you can make any change on controls using this event)

3. RunWorkerCompleted:
It occur after the whole process on DoWork is completed.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Are you creating just ONE instance of clsThreadWritebackBatch() at a time and waiting for the results?
...or do you need lots of these things running at the same time?
0
 
onemorecokeAuthor Commented:
For this specific process, yes just one.  My next situation though is launching multiple threads with the same class.
0
 
nepaluzCommented:
I do not know whether you dislike my advice, however, the best by far example would be the walk-through that I gave you earlier.

The walk-through shows you how to create a class implementing the background worker. It is simple and concise and its up to you how far you want to take it from there. I will give you the link again

http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx
0
 
Mohamed AbowardaSoftware EngineerCommented:
@onemorecoke: Have you tried to use BackgroundWorker as I posted above?

It will solve your issue.
0
 
onemorecokeAuthor Commented:
Medo3337, I am experimenting to see what works best for my situation, thanks for checking in.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
The link by nepaluz does give a good example.

Basically INSIDE your clsThreadWritebackBatch() class you would encapsulate a BackgroundWorker() control and in the DoWork() handler you execute your code that is now in your manual thread.  You pass the result to the RunWorkerCompleted() event and from there you can raise you classes FinishedBatch() event.
0
 
onemorecokeAuthor Commented:
Ok, thanks.  Last question, just trying to decide on using a backgroundworker component or manual method.  Can you set thread priority using the backgroundworker component or is that something that I will have to use the manual method for?  Thanks everyone.

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Don't think you can set the priority on the backgroundworker...
0
 
Mohamed AbowardaSoftware EngineerCommented:
If you want to set the thread priority you will have to use Threading class:
http://www.java2s.com/Code/VB/Thread/ThreadpriorityHighestandnormal.htm
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 6
  • 5
  • 5
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now