Link to home
Start Free TrialLog in
Avatar of Mr_Fulano
Mr_FulanoFlag for United States of America

asked on

BackgroundWorker Problem

Hi, I'm using VB.NET2010 (VS2010) WinForms. I have a method called "parseFile()" that parses a TXT file and writes to a Textbox Control as it performs a calculation on each row of dataTable, which I create within that method.  -- All that works well. (No problems so far...)

I then tried to add a BackgroundWorker, so that I can see the progress of my method as it parses the TXT file and so that I can add a progress bar to my Form, thus allowing me to let users know how far along the calculations are going.

However, once I added the BackgroundWorker, I get this error:

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

Note: ("tbxOutPut" is my Textbox Control)

The Texbox was created in the designer by adding a Textbox Control to the Form.


Below is the code that calls the BackgroundWorker. The line of code it stops on is below, which is the first time I access the Textbox Control once the method has begun.

>>  tbxOutPut.Clear() <--- I get the error here in my code

I know that I'm accessing one thread from within another. I know that is unsafe. However, I don't know how to do it in a "safe" manner - other than rewriting all my code and splitting the Textbox access to another method, which is not something trivial - nor something I'm willing to do, so I would really like to find a way to correct this error.

I tried also to look this up and found this post, but I'm still confused.

http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(EHINVALIDOPERATION.WINFORMS.ILLEGALCROSSTHREADCALL);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-VB)&rd=true


Thanks,
Fulano
Private Sub btnParseFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnParseFile.Click
        BackgroundWorker1.RunWorkerAsync(btnParseFile)
    End Sub

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        parseFile()
    End Sub

Open in new window

SOLUTION
Avatar of Wayne Taylor (webtubbs)
Wayne Taylor (webtubbs)
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mr_Fulano

ASKER

Hi webtubs, so what you mean is that each time I need to reach out to the Textbox control I need to use the ReportProgress event?

Fulano
That's correct.  You can pass a progress percentage number with the first parameter, and anything with the second parameter:

     BackgroundWorker1.ReportProgess(someNumberVariableHereForPercentage, ClassInstanceOrSimpleStringHere)

This will cause the ProgressChanged() event to fire where you can retrieve the values and update the GUI without causing the cross-thread error:

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
        tbxOutPut.AppendText(e.UserState & vbCrLf)
    End Sub
Make sure you set the WorkerReportsProgress property of the BGW to True as its false by default :-)


Also, given that you are parsing and processing a text file line by line, a progressbar may not be suitable. Incrementing a count of processed rows on the UI may be more suitable.
I think CodeCruiser may be right...the BackgroundWorker may not be the best solution - for the way my code is written. THe BGW was an afterthought, so next time I'll have to plan for it and design my code accordingly.

Also from what Idle_Mind and Webtubbs are saying, the BGW is not going to work well with my code. I hit that Textbox way too many times (for each line I process) and using a BGW to come up for air on each line is not ideal.

OK...maybe back to the drawing board for me.

Fulano
Approximately how many lines are there in a typical file that you are processing?
I did not say the BGW is not appropriate. I think a progressbar is not suitable in this case. You can use a label to update the number of rows that you have processed.

> I hit that Textbox way too many times (for each line I process) and using a BGW to come up for air on each line is not ideal.

I think it would be still better than a frozen UI.
Hi Guys, to answer Idle_Mind's question...it can be anywhere from 15K lines to 450K lines. So, I need to show the user where he/she is in the process somehow.

If a BGW is still the best approach (progress bar or not) I will need to modify the code so that the textbox threading is in a method all by itself. I think I can do that, but it will take some working around what I already have.

Thanks,
Fulano
How long does it take to process those lines? Progressbar would not be suitable here as dividing 100 by 450K would yield a very little step value for the progressbar which would make it look like the progressbar is not changing at all. Processed row count is the way to go in my opinion.
It takes maybe 7-8 minutes to process 15K lines and about 15-20 minutes to process 450K lines.

Would a percent value type of label not be about the same? I would think that the label would hang on each number for a short while before it worked its way up to the next value - maybe I'm not seeing this clearly.

Thanks,
Fulano
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry for the delay. I was working on getting to know the BGW a bit more before closing this out. I used most of Idle_Mind's approach, and what Webtubbs suggested about the ProgressChanged event. Together they worked out great.

Thank you all!!!