I always thought that a program read and executed instructions in the order in which they were written; but I'm finding that in my current experimental program it reads all of the code in a procedure and then does the execution. Let me explain: I have a windows form on which there are quite a number of textboxes. The variables are populated from txtfiles. What I wanted was for, say, the first five textboxes to be populated and then another five, and so on. The reason being that because there are so many, and the txtfiles are quite large, it's a slow-ish read and I didn't want the user looking at a blank screen thinking it had crashed whilst the data was being pulled in. I coded in this way, but no matter how I code, none of the textboxes get populated until the whole procedural code has been read. First question - is this normal or have I missed a step?
I put a label on the form saying "Getting data - please wait"; designing it to be visible during the loading process; but all that happens is that I get the outline of the label rather than the label itself. Why?
Put very simply, you have blocked the UI Thread due to all the processing required to read your files. The UI Thread is the “User Interface” thread and is basically the pen that draws everything to the screen and if you use all the processing power allocated to the UI Thread to do other things (like reading files) then nothing gets drawn to the screen until that work is completed. It’s gets a lot more technical than this but that is the very basics.
The way you get round this is to use another Thread to read the files and then pass the necessary information to the UI thread as and when a portion of work gets completed. There are various ways to do this but the one I would recommend that you learn first is the BackgroundWorker.
Have a read of all this and keep at it until it all sinks in:-
Wow. Thanks for the info. I've read through it all and at the moment it makes no sense as to where I'd fit it into my program; but I'll keep going!!! Thanks again
One of the things you have to realize about object oriented programming is that while yes the code still executes in the order it's written the time that blocks of code can run in different sequences.
For example: Events, it's code that only runs when the event happens, so your code inside the button click event sub will execute in the order it's written but that block only runs when called (the button is clicked).
While my example above actually explains your data loading/displaying issue let me add more detail, you have a thread-busy sub that's loading the data and assigning the variable values to the textboxes is it goes, you're assigning the value vie the Text property, which causes the control to have a "refresh" event happen that actually displays the new value, which it will do so once the thread isn't busy, which would be when you're done loading the data. Now there's two ways to handle this situation, you could (though not recommended) force your data execution to allow the form & it's controls to "refresh", ie process the event queue, every so often, or as mentioned already you could use threading. You can do threading yourself if you wish, but it does get a bit messy pretty quickly, or as suggested you can use the BackgroundWorker component in which you have a DoWork event that runs code on a different thread which is where you would want your data loading code to be and you use the BackgroundWorker.ReportProgress() call to have it's ProgressChanged event on the form's thread fire where you can update the Label(s) appropriately and the user will see the data update on the form in real time.
You could set a Label to say "data loading" or whatever then start the background worker and of course when the RunWorkerCompleted fires you know the data is done loading so you can hide the loading data label and enable the buttons and toolbar stuff for the user to now use the form.
So This is the code I have for when the user clicks a button on the form (sorry; it's a bit long-winded). Where would I place the code for the BackgroundWorker ?
Private Sub btnPrice_Click(sender As Object, e As EventArgs) Handles btnPrice.Click
Dim eGraphics As Graphics = Me.CreateGraphics
Dim myPen As Pen = New Pen(Drawing.Color.Black, 1)
MyTend.read1()
tbAAH.Text = Tender.AAH(a)
tbCol.Text = Tender.COL(a)
tbDE.Text = Tender.DE(a)
tbLex.Text = Tender.LEX(a)
tbUni.Text = Tender.UNI(a)
'Populate temp textboxes for DTB ranking
TextBox1.Text = tbAAH.Text
TextBox2.Text = tbCol.Text
TextBox3.Text = tbDE.Text
TextBox4.Text = tbLex.Text
TextBox5.Text = tbUni.Text
'Populate DTW tender details
MyTend.read2()
tbAct.Text = Tender.ACT(a)
tbBWay.Text = Tender.BWay(a)
tbBrist.Text = Tender.BRI(a)
tbCST.Text = Tender.CST(a)
tbDex.Text = Tender.DEX(a)
tbEth.Text = Tender.ETH(a)
tbMaw.Text = Tender.MAW(a)
tbMedh.Text = Tender.MEDh(a)
tbMedw.Text = Tender.MEDw(a)
tbMyl.Text = Tender.MYL(a)
tbOTC.Text = Tender.OTC(a)
tbPri.Text = Tender.PRI(a)
tbTev.Text = Tender.TEV(a)
tbTri.Text = Tender.TRI(a)
tbWay.Text = Tender.WAY(a)
'Find DTB minimum value and highlight in green the cheapest DTB tenders
Dim textBoxes() As TextBox = {tbAAH, tbCol, tbDE, tbLex, tbUni} 'make an array of textboxes for DTB companies
Dim Bnumbers As New List(Of Double)
Dim minNumberB As Double
Dim o As Integer
For Each tb As TextBox In textBoxes
If Double.TryParse(tb.Text, o) Then
Bnumbers.Add(tb.Text) 'if the textbox contains a number, add it to the list
End If
Next
If Bnumbers.Count > 0 Then
'at least one textbox contains number
minNumberB = Bnumbers.Min
tbDTBmin.Text = minNumberB
End If
For Each tb As TextBox In textBoxes
If tb.Text = tbDTBmin.Text Then
tb.BackColor = Color.LawnGreen
End If
If tb.Text <> "~" Then
tb.Text = FormatCurrency(tb.Text, 2)
End If
Next
'
'Rank the DTB tenders
Dim lb As New ListBox
Dim Ascendinglb As New List(Of Decimal)
Dim ItemToAdd As Decimal
For x As Integer = 1 To 5
Dim tb = Me.Controls("TextBox" & x)
If Decimal.TryParse(tb.Text, ItemToAdd) Then
lb.Items.Add(ItemToAdd)
tb.Text = ""
End If
Next
If lb.Items.Count > 1 Then
Ascendinglb.Clear()
For i = 0 To lb.Items.Count - 1
Ascendinglb.Add(CDbl(lb.Items(i)))
Next
Ascendinglb.Sort()
lb.Items.Clear()
For i = 0 To Ascendinglb.Count - 1
Dim tb = Me.Controls("TextBox" & i + 1)
tb.Text = Ascendinglb(i).ToString
tb.Text = FormatCurrency(tb.Text, 2)
Next
End If
''
If tbRk3.Text = "1" Or tbRk6.Text = "1" Then
If tbAAH.Text <> "~" Then
If tbAAH.Text = TextBox1.Text Then
tbRk1.Text = 2
End If
If tbAAH.Text = TextBox2.Text Then
tbRk1.Text = 3
End If
If tbAAH.Text = TextBox3.Text Then
tbRk1.Text = 4
End If
If tbAAH.Text = TextBox4.Text Then
tbRk1.Text = 5
End If
If tbAAH.Text = TextBox5.Text Then
tbRk1.Text = 6
End If
End If
If tbCol.Text <> "~" Then
If tbCol.Text = TextBox1.Text Then
tbRk2.Text = 2
End If
If tbCol.Text = TextBox2.Text Then
tbRk2.Text = 3
End If
If tbCol.Text = TextBox3.Text Then
tbRk2.Text = 4
End If
If tbCol.Text = TextBox4.Text Then
tbRk2.Text = 5
End If
If tbCol.Text = TextBox5.Text Then
tbRk2.Text = 6
End If
End If
If tbDE.Text <> "~" Then
If tbDE.Text = TextBox1.Text Then
tbRk3.Text = 2
End If
If tbDE.Text = TextBox2.Text Then
tbRk3.Text = 3
End If
If tbDE.Text = TextBox3.Text Then
tbRk3.Text = 4
End If
If tbDE.Text = TextBox4.Text Then
tbRk3.Text = 5
End If
If tbDE.Text = TextBox5.Text Then
tbRk3.Text = 6
End If
End If
If tbLex.Text <> "~" Then
If tbLex.Text = TextBox1.Text Then
tbRk4.Text = 2
End If
If tbLex.Text = TextBox2.Text Then
tbRk4.Text = 3
End If
If tbLex.Text = TextBox3.Text Then
tbRk4.Text = 4
End If
If tbLex.Text = TextBox4.Text Then
tbRk4.Text = 5
End If
If tbLex.Text = TextBox5.Text Then
tbRk4.Text = 6
End If
End If
If tbUni.Text <> "~" Then
If tbUni.Text = TextBox1.Text Then
tbRk5.Text = 2
End If
If tbUni.Text = TextBox2.Text Then
tbRk5.Text = 3
End If
If tbUni.Text = TextBox3.Text Then
tbRk5.Text = 4
End If
If tbUni.Text = TextBox4.Text Then
tbRk5.Text = 5
End If
If tbUni.Text = TextBox5.Text Then
tbRk5.Text = 6
End If
End If
Else
If tbAAH.Text <> "~" Then
If tbAAH.Text = TextBox1.Text Then
tbRk1.Text = 1
End If
If tbAAH.Text = TextBox2.Text Then
tbRk1.Text = 2
End If
If tbAAH.Text = TextBox3.Text Then
tbRk1.Text = 3
End If
If tbAAH.Text = TextBox4.Text Then
tbRk1.Text = 4
End If
If tbAAH.Text = TextBox5.Text Then
tbRk1.Text = 5
End If
End If
If tbCol.Text <> "~" Then
If tbCol.Text = TextBox1.Text Then
tbRk2.Text = 1
End If
If tbCol.Text = TextBox2.Text Then
tbRk2.Text = 2
End If
If tbCol.Text = TextBox3.Text Then
tbRk2.Text = 3
End If
If tbCol.Text = TextBox4.Text Then
tbRk2.Text = 4
End If
If tbCol.Text = TextBox5.Text Then
tbRk2.Text = 5
End If
End If
If tbDE.Text <> "~" Then
If tbDE.Text = TextBox1.Text Then
tbRk3.Text = 1
End If
If tbDE.Text = TextBox2.Text Then
tbRk3.Text = 2
End If
If tbDE.Text = TextBox3.Text Then
tbRk3.Text = 3
End If
If tbDE.Text = TextBox4.Text Then
tbRk3.Text = 4
End If
If tbDE.Text = TextBox5.Text Then
tbRk3.Text = 5
End If
End If
If tbLex.Text <> "~" Then
If tbLex.Text = TextBox1.Text Then
tbRk4.Text = 1
End If
If tbLex.Text = TextBox2.Text Then
tbRk4.Text = 2
End If
If tbLex.Text = TextBox3.Text Then
tbRk4.Text = 3
End If
If tbLex.Text = TextBox4.Text Then
tbRk4.Text = 4
End If
If tbLex.Text = TextBox5.Text Then
tbRk4.Text = 5
End If
End If
If tbUni.Text <> "~" Then
If tbUni.Text = TextBox1.Text Then
tbRk5.Text = 1
End If
If tbUni.Text = TextBox2.Text Then
tbRk5.Text = 2
End If
If tbUni.Text = TextBox3.Text Then
tbRk5.Text = 3
End If
If tbUni.Text = TextBox4.Text Then
tbRk5.Text = 4
End If
If tbUni.Text = TextBox5.Text Then
tbRk5.Text = 5
End If
End If
End If
'Find DTW minimum value
Dim textBoxesW() As TextBox = {tbAct, tbBWay, tbBrist, tbCST, tbDex, tbEth, tbMaw, tbMedh, tbMedw, tbMyl, tbOTC, tbTev, tbTri, tbWay} 'make an array of textboxes for DTW companies
Dim Wnumbers As New List(Of Double)
Dim minNumberW As Double
For Each tb As TextBox In textBoxesW
If Double.TryParse(tb.Text, o) Then
Wnumbers.Add(tb.Text)
End If
Next
If Wnumbers.Count > 0 Then
minNumberW = Wnumbers.Min
tbDTWmin.Text = minNumberW
End If
For Each tb As TextBox In textBoxesW
If tb.Text = tbDTWmin.Text Then
tb.BackColor = Color.LawnGreen
End If
If tb.Text <> "~" Then
tb.Text = FormatCurrency(tb.Text, 2)
End If
Next
'Allocate CRW and NP8 in Ranking (tbRk6 is for Chester Rd and tbRk3 is for DE)
If tbCRW.Text = "Yes" Or tbCRW.Text = "Y" Then
tbRk6.Text = "1"
End If
If tbNP8.Text = "Y" Or tbNP8.Text = "Yes" Then
lblNP8.Visible = True
tbRk3.Text = "1"
End If
'Display full drug family based on GRPNo
MyDetails.read2()
MyTend.read3()
eGraphics.DrawRectangle(myPen, 418, 215, 190, 620)
Dim cte As Long = 0
For i = 0 To 39999
If DetRead.GRPNo(i) = tbGrpNo.Text And tbGrpNo.Text <> "~" Then
cte = cte + 1
a = i
If DetRead.GRPNo(i) = tbGrpNo.Text And DetRead.BGP(i) = "P" Then
tbPAAH.Visible = True
tbPCol.Visible = True
tbPDE.Visible = True
tbPLex.Visible = True
tbPUni.Visible = True
tbPMaw.Visible = True
tbPMed.Visible = True
tbPShak.Visible = True
tbPTri.Visible = True
tbPWay.Visible = True
tbPAAH.Text = Tender.PAAH(i)
tbPCol.Text = Tender.PCOL(i)
tbPCST.Text = Tender.PCST(i)
tbPDE.Text = Tender.PDE(i)
tbPLex.Text = Tender.PLEX(i)
tbPUni.Text = Tender.PUNI(i)
tbPMaw.Text = Tender.PMAW(i)
tbPMed.Text = Tender.PMED(i)
tbPShak.Text = Tender.PSHA(i)
tbPTri.Text = Tender.PTRI(i)
tbPWay.Text = Tender.PWAY(i)
End If
If cte = 1 Then
lblFam.Visible = True
tbFam1.Visible = True
tbFam1.Text = ReadWrite.Prods(i)
End If
If cte = 2 Then
tbFam2.Visible = True
tbFam2.Text = ReadWrite.Prods(i)
End If
If cte = 3 Then
tbFam3.Visible = True
tbFam3.Text = ReadWrite.Prods(i)
End If
If cte = 4 Then
tbFam4.Visible = True
tbFam4.Text = ReadWrite.Prods(i)
End If
If cte = 5 Then
tbFam5.Visible = True
tbFam5.Text = ReadWrite.Prods(i)
End If
If cte = 6 Then
tbFam6.Visible = True
tbFam6.Text = ReadWrite.Prods(i)
End If
If cte = 7 Then
tbFam7.Visible = True
tbFam7.Text = ReadWrite.Prods(i)
End If
If cte = 8 Then
tbFam8.Visible = True
tbFam8.Text = ReadWrite.Prods(i)
End If
If cte = 9 Then
tbFam9.Visible = True
tbFam9.Text = ReadWrite.Prods(i)
End If
If cte = 10 Then
tbFam10.Visible = True
tbFam10.Text = ReadWrite.Prods(i)
End If
If cte = 11 Then
tbFam11.Visible = True
tbFam11.Text = ReadWrite.Prods(i)
End If
If cte = 12 Then
tbFam12.Visible = True
tbFam12.Text = ReadWrite.Prods(i)
End If
If cte = 13 Then
tbFam13.Visible = True
tbFam13.Text = ReadWrite.Prods(i)
End If
If cte = 14 Then
tbFam14.Visible = True
tbFam14.Text = ReadWrite.Prods(i)
End If
eGraphics.DrawRectangle(myPen, 608, 215, 245, 620)
End If
Next
'Find minimum PI tender price
Dim textBoxesPI() As TextBox = {tbPAAH, tbPLex, tbPCol, tbPDE, tbPUni, tbPCST, tbPMaw, tbPShak, tbPMed, tbPTri, tbPWay} 'make an array of your textboxes for PI products
Dim PInumbers As New List(Of Double)
Dim minNumberPI As Double
For Each tb As TextBox In textBoxesPI
If Double.TryParse(tb.Text, o) Then
PInumbers.Add(tb.Text) 'if the textbox contains a number, add it to the list
End If
Next
If PInumbers.Count > 0 Then
'at least one textbox contains number
minNumberPI = PInumbers.Min
tbPImin.Text = minNumberPI
End If
For Each tb As TextBox In textBoxesPI
If tb.Text = tbPImin.Text Then
tb.BackColor = Color.LawnGreen
End If
If tb.Text <> "~" Then
tb.Text = FormatCurrency(tb.Text, 2)
End If
Next
eGraphics.DrawRectangle(myPen, 8, 215, 225, 275)
eGraphics.DrawRectangle(myPen, 233, 215, 185, 620)
End Sub
The first thing to note is that you need to remember to wrap you code in Code Tags and not Quote Tags to make things easier to read but 10 out of 10 for trying.
As to your code, I am not even going to try to read it and figure out where you need to place the BacgroundWorker. The only thing I will repeat is to keep going over the link I supplied until in really does sink in. Forget your current program and write the example programs given in the link to fully realise why things are working the way they do. You will only realise the full potential of Multi-Threading by experimentation and experience.
Cor. That's quite a block of code. Tell you what, for this iteration of the program don't bother with the background worker, just put this at the start of your FOR loop that does 4000 things:
VB.NET:
If i Mod 10 = 0 Then Application.DoEvents()
viz:
VB.NET:
For i = 0 To 39999
If i Mod 10 = 0 Then Application.DoEvents()
If DetRead.GRPNo(i) = tbGrpNo.Text And tbGrpNo.Text <> "~" Then
Yes, it's dirty but.. erm.. so are a lot of the other things in there
"We'll solve em in the rewrite"
Oh, and if those drawrectangle() calls are supposed to be some sort of progress bar, put Application.DoEvents() after those too (but in the loop, mod it by 10 or more, as per above)
Ok Guys. I know the code is messy, but I'm completely new to vb programming so tend to write things down as I want them to happen. No doubt when everything works I'll get down to re-writing and simplifying the code. In the meantime I've worked out how to make the BackgroundWorker do its job. It now handles the time consuming process of reading text files into variables; however, the one thing I haven't figured out is how to make a ProgressBar work. Any help on that would be appreciated. Incidentally the DrawRectangle codes are nothing to do with Progress bar; simply a way of drawing rectangles around blocks of textboxes on the form to make the form clearer to read.
As is always the case, if you want to report absolute progress then you have to be able to calculate it. It's up to you how you do that, e.g. simply divide the number of files processed by the total number and multiply by 100 to get a percentage. You then call the ReportProgress method of the BackgroundWorker in the DoWork event handler each time you want to update the progress and you actually update the UI with the progress in the ProgressChanged event handler. Here's one I prepared earlier:
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.