Problem With DoEvents

J

Justin

I can attach my code if anyone wants to see it however I'll try to ask my
question with some mark up code first.

I'm having a problem terminating my process while using DoEvents. For
example:

Button.text = start

If button.text = start then
button.text = stop
msgbox "Boo!"
doevent
while 1=1
msgbox "BooHoo!"
loop
else if button.text = stop
button.text = start
msgbox "Quit Your Whining"
end if


Ok, click the button and you get:
Boo!
BooHoo!
BooHoo!
BooHoo!
BooHoo!
BooHoo!
BooHoo!
.......

Now click the stop button and you get

Quit Your Whining
BooHoo!

That doesn't make sense. The button already did NOT = Start. It was Stop
which is why it ran the stop code.

For some reason it goes through the DoEvents code one last time.

How can I properly stop that DoEvents thread prior to running my STOP code?

Thanks for any advise!
 
B

Branco Medeiros

Justin wrote:
I'm having a problem terminating my process while using DoEvents. For
example:

Button.text = start

If button.text = start then
button.text = stop
msgbox "Boo!"
doevent
while 1=1
msgbox "BooHoo!"
loop
else if button.text = stop
button.text = start
msgbox "Quit Your Whining"
end if
Now click the stop button and you get

Quit Your Whining
BooHoo!

That doesn't make sense. The button already did NOT = Start. It was Stop
which is why it ran the stop code.

For some reason it goes through the DoEvents code one last time.
<snip>

I don't think your markup translates the sequence of actions from your
code very faithfully. For instance, the markup code only calls DoEvents
once, and it seems you're expecting it to run several times. Maybe
revising the markup or posting the actual code would provide a better
view of the problem.

Keep in mind, however, that DoEvents in VB.Net can be even more
dangerous/unpredictable/undebuggable than in VB classic, cause VB.Net
must account for many more things in the event processing cycle. For
Example, launch a "DoEvents" from the meain thread when performing
inter-thread UI updates and you may crash the application.

There are other ways to accomplish what you (seem to) want, and
DoEvents is way down in this list, if even there at all.

HTH.

Regards,

Branco.
 
T

Tom Leylan

Before you get more confused... (this has (as far as I can see) nothing to
do with threading)

As was pointed out your pseudocode isn't likely the same as the code you
wrote. But your question also indicates there is a misunderstanding since
you write "it goes through the DoEvents code one more time". There is no
"DoEvents code" there is simply a call to DoEvents which gives the O/S a
chance to process low-priority events that are not getting processed.

Also try to avoid constructs like: while 1 = 1. It is an uncontrollable
condition which is a) poor form and b) overly complex since 1 = 1 is equal
to True why not just loop while True? But again don't do that just give it
an honest condition to test for.

I think you would be better off posting 1) a description of what you are
attempting and 2) the actual code (reduced to the essentials if it is
particularly long.) Perhaps even 3) why you doing this since it is going to
be very annoying when it's running :)

Tom
 
J

Justin

Ok, here's the code. What I'm doing is setting up a connection to an RFID
Radio then going out to my SAP ERP system and obtaining pallet information.
Then I loop through and compare the known pallet info with what is actualy
being read on the physical pallet. The goal is to make sure what is on the
pallet is what should be on the pallet. If not then the drivers needs to be
able to see what is on the pallet that either shouldn't be or is not on
there and should be.

The images are the indicator to the driver as to what he/she should do.

Private Sub btnExecute_Click(ByVal eventSender As System.Object, ByVal
eventArgs As System.EventArgs) Handles btnExecute.Click

Dim tags() As TagInfo
Dim i As Short
Dim bParseResult As Boolean
Dim SAPArray As New ArrayList()
Dim SAPArrayDone As Boolean
Dim PalletLabel As Boolean
Dim TagCheck As Boolean
Dim dsTagsFound As New DataSet
Dim dtTagsFound As New DataTable
Dim drTagsFound As DataRow
Dim Foreign As Boolean
dtTagsFound.Columns.Add(New DataColumn("TagID", GetType(String)))
dtTagsFound.Columns.Add(New DataColumn("Count", GetType(String)))
dtTagsFound.Columns.Add(New DataColumn("Serial", GetType(String)))
dtTagsFound.Columns.Add(New DataColumn("TagFound", GetType(String)))
dsTagsFound.Tables.Add(dtTagsFound)

If btnExecute.Text = "Start" Then

mbAuto = True

' Flash HALF the lights to let the operator know his action did
something.
pbTrafficLight.Image = Image.FromFile("Images\light_red.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image = Image.FromFile("Images\light_yellow.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)

While mbAuto = True

'Get tags from reader
If Reader.IsConnected Then

' Once everything is OK then continue with the green
light and turn it off
If btnExecute.Text = "Start" Then
pbTrafficLight.Image =
Image.FromFile("Images\light_green.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image =
Image.FromFile("Images\light_off.png")
Me.Refresh()
End If

btnExecute.Text = "Stop"
msTagList = Reader.TagList

Else
mbAuto = False

' Connection failed so flash the red light three times
pbTrafficLight.Image =
Image.FromFile("Images\light_red.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image =
Image.FromFile("Images\light_off.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image =
Image.FromFile("Images\light_red.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image =
Image.FromFile("Images\light_off.png")
Me.Refresh()
System.Threading.Thread.Sleep(500)
pbTrafficLight.Image =
Image.FromFile("Images\light_red.png")
Me.Refresh()
End If


**********everything after this line runs ONE MORE time when I click my stop
button.


System.Windows.Forms.Application.DoEvents()

'Parse tag data and dump into grid
On Error GoTo errHandler

'This is how many tags the reader currently sees, so if true
then do work.
bParseResult = AlienUtils.ParseTagList(msTagList, tags)
If (bParseResult) Then

For i = 0 To UBound(tags)

If Mid(tags(i).TagID, 1, 2) = "31" Then
PalletLabel = True
pbTrafficLight.Image =
Image.FromFile("Images\light_Yellow.png")


' Here I'm going to jump out to SAP and grab the
serial numbers I need.
' I'm going to dump them into an array or
dataset. So I'm only going to
' Do this is that resulting array or dataset is
empty.
If SAPArrayDone = False Then
SAPArray.Clear()

Dim Packitems As ZDEL_PACKITEMS
Dim Pallet As ZDEL_PALLET

Dim tblPackitems As New ZDEL_PACKITEMSTable
Dim tblPallet As New ZDEL_PALLETTable

Dim rfc As
BAPIZRFID_DETAILS.BAPIZRFID_DETAILS = New
BAPIZRFID_DETAILS.BAPIZRFID_DETAILS
rfc.Connection =
SAP.Connector.SAPConnection.GetNewConnection("ASHOST=169.254.2.200 SYSNR=00
CLIENT=300 USER=LINK PASSWD=access")
rfc.Zrfid_Details("00" &
GetSSCCCheckDigit("10090159" & GetTagInfo(tags(i).TagID)(5)), tblPackitems,
tblPallet)

For Each Packitems In tblPackitems
SAPArray.Add(Mid(Packitems.Exidv, 13,
7))
Next

For Each Pallet In tblPallet
SAPArray.Add(RemoveLeadingZeros(Mid(Pallet.Exidv,
11, 9)))
Next

SAPArray.Sort()
SAPArrayDone = True


End If
End If

If PalletLabel = True Then

' Here I loop through the columns, find one to
sort and set column widths
Dim theColumn As DataGridViewColumn
For Each theColumn In Me.gvTagsFound.Columns
If theColumn.HeaderText = "TagID" Then
gvTagsFound.Columns("TagID").Width = 175
ElseIf theColumn.HeaderText = "Count" Then
gvTagsFound.Columns("Count").Width = 40
ElseIf theColumn.HeaderText = "Serial" Then
gvTagsFound.Columns("Serial").Width = 75
ElseIf theColumn.HeaderText = "TagFound"
Then
gvTagsFound.Sort(theColumn,
System.ComponentModel.ListSortDirection.Ascending)
End If
Next

gvTagsFound.DataSource = dtTagsFound
gvTagsFound.Columns("TagFound").Visible = False

TagCheck = False

For Each dr As DataRow In
dsTagsFound.Tables(0).Rows
If dr("TagID") = tags(i).TagID Then
TagCheck = True
dr("Count") = dr("Count") +
tags(i).ReadCount
dsTagsFound.Tables(0).AcceptChanges()
End If
Next

If Not TagCheck Then
drTagsFound = dtTagsFound.NewRow()
drTagsFound("TagID") = tags(i).TagID
drTagsFound("Count") = tags(i).ReadCount
drTagsFound("Serial") =
RemoveLeadingZeros(CStr(GetTagInfo(tags(i).TagID)(5)))

' Here I perform a search on the SAP
ArrayList (SAPArray) and when I
' find a match between the array and the
dataset I mark the field
' as found

Dim index As Integer =
SAPArray.BinarySearch(RemoveLeadingZeros(CStr(GetTagInfo(tags(i).TagID)(5))),
New CaseInsensitiveComparer())

If index < 0 Then
drTagsFound("TagFound") = "0"
Else
drTagsFound("TagFound") = "1"
SAPArray.RemoveAt(index)
End If

' At the end of the gridview is a blank
record.
' This kills that blank record
Dim cm As CurrencyManager =
BindingContext(gvTagsFound.DataSource, gvTagsFound.DataMember)
Dim dv As DataView = cm.List
dv.AllowNew = False

dtTagsFound.Rows.Add(drTagsFound)
End If

End If

Next

' Here I lookp through all the rows and set the GRIDVIEW
row color
' I'd rather set this color in the gridview above as I
insert the rows???
' Then I set the Foreign variable approprietly for green
light determination
Dim theRow As DataGridViewRow

For Each theRow In gvTagsFound.Rows
If theRow.Cells(3).Value = "0" Then
theRow.DefaultCellStyle.BackColor = Color.Red
Foreign = True
End If
Next

lbTagsNotFound.DataSource = Nothing
lbTagsNotFound.DataSource = SAPArray



*******When I click my stop button I change this image. However this code
is firing one more time to change it back to either green or red.


' Here we need to see if we've found enough tags to give
a green light. Later, this will be a percentage
If lbTagsNotFound.Items.Count < 2 And PalletLabel = True
And Foreign = False Then
pbTrafficLight.Image =
Image.FromFile("Images\light_green.png")
ElseIf Foreign = True Then
pbTrafficLight.Image =
Image.FromFile("Images\light_red.png")
End If


Else
'Blow everthing out
PalletLabel = False
gvTagsFound.DataSource = Nothing
dsTagsFound.Clear()
dtTagsFound.Clear()
SAPArray.Clear()
lbTagsNotFound.DataSource = Nothing
SAPArrayDone = False
pbTrafficLight.Image =
Image.FromFile("Images\light_off.png")
Foreign = False
End If

End While

ElseIf btnExecute.Text = "Stop" Then
btnExecute.Text = "Start"
mbAuto = False
pbTrafficLight.Image = Image.FromFile("Images\light_off.png")
' Need to add visual labels that will need to be reset here.
End If

Exit Sub


The problem is, when I click STOP it changes the image but then it goes
through the above code one more time and resets the image whatever it was
set to before. I marked the code above that is the offending code that
changes the image back to something else. However placing a msgbox anywhere
after the DoEvents line fires that msgbox when my stop button is clicked.
That and that alone is my reasoning for the DoEvents being at fault.
 
J

Justin

Were you wanting me to sleep before I run my stop code? That doesn't work.
It sleeps, runs my stop code then again, runs through everything after
DoEvents one more time.



Thanks, Justin Emlay System Administrator Maisto International, Inc.
909-357-7988 ext.360 909-357-9958 fax (e-mail address removed) www.maisto.com
 
J

Justin

By "DoEvents code" I meant that it runs through all code after the DoEvent
call "one more time".

By showing 1=1 I was sparing everyone the lengthy details of the project.
There is more reasonable code being used.

As for 1, 2 and 3 I've already done that in a reply to Branco.



Thanks, Justin Emlay System Administrator Maisto International, Inc.
909-357-7988 ext.360 909-357-9958 fax (e-mail address removed) www.maisto.com
 
S

Stephany Young

When the button is clicked while the caption is 'Start', you enter a loop
that is only terminated when mbAuto is reset and, even then, only at the
beginning of an itteration of the loop.

When the button is clicked while the caption is 'Stop', you reset mbAuto,
but the current iteration of the loop (see above) must fully complete before
the loop can terminate. The results you observe will vary depending on how
far the current iteration of the loop is through the logic when mbAuto is
reset.
 
B

Branco Medeiros

Justin said:
Ok, here's the code. What I'm doing is setting up a connection to an RFID
Radio then going out to my SAP ERP system and obtaining pallet information.
Then I loop through and compare the known pallet info with what is actualy
being read on the physical pallet. The goal is to make sure what is on the
pallet is what should be on the pallet. If not then the drivers needs to be
able to see what is on the pallet that either shouldn't be or is not on
there and should be.

The images are the indicator to the driver as to what he/she should do.

The problem is, when I click STOP it changes the image but then it goes
through the above code one more time and resets the image whatever it was
set to before. I marked the code above that is the offending code that
changes the image back to something else. However placing a msgbox anywhere
after the DoEvents line fires that msgbox when my stop button is clicked.
That and that alone is my reasoning for the DoEvents being at fault.

Without going into the code merits (or lack of them =)), a superficial
analisys of the execution flow reveals that, for the specific problem
of the duplicating action, the location of DoEvents in your code is the
culprit (I'm not going into other issues, by now).

See, you call DoEvents just before executing the instructions that
process the device's data. In practice this *inlines a call* to the
click event (if the button was clicked, of course), which will set
mbAuto to False. But then, after DoEvents returns, you *continue
processing the remaining code*, as if nothing had happened. Just when
it gets to the end of the loop is that you check mbAuto, but then an
extra cicle was already performed.

It would be something like this:

Do While mbAuto
If is conected then
Set the label to "stop" <- this will happen repeatedly
Loads the Reader's tags
Else
Disable mbAuto <- Oops, one more cicle will follow!
End If

DoEvents
(or, actually something like this:
If Button was clicked then
Disable mbAuto
Pretend we are finished
End If
)

Probe the device and load data

Loop

A *paliative* approach would be:

set the label to "stop"
Do While mbAuto
If is conected then
Read the Reader's tags
Probe the device and load data
DoEvents() <-- allows a click on "stop"
Else
Disable mbAuto
End If
Loop

Personally, I'd encapsulate the light flashing and the actual cicles
into a separate class with its full set of events, etc.

HTH.

Regards,

Branco
 
J

Justin

I took your first piece of advise and ditched the DoEvents. I'm setting it
up now where it finds a pallet label and starts a new thread. However with
my first attempt (aside from updating form object issues, unsafe thread)
when I went to kill the thread it AGAIN went through and ran the code in the
thread one last time.

I need to play with it more.

Thanks to everyone and their input!!!!!







Thanks, Justin Emlay System Administrator Maisto International, Inc.
909-357-7988 ext.360 909-357-9958 fax (e-mail address removed) www.maisto.com
 
R

Robert

Branco Medeiros said:
Without going into the code merits (or lack of them =)), a superficial
analisys of the execution flow reveals that, for the specific problem
of the duplicating action, the location of DoEvents in your code is the
culprit (I'm not going into other issues, by now).


Has he ever heard of subroutines? I hope so if he is working on ERP
stuff..
 
J

Justin

I only subroutine things that would otherwise cause duplicate code. If you
look through the code again you will find many functions that otherwise
don't exist to dotnet. So by my code alone, the answer to your question is
yes.



Thanks, Justin Emlay System Administrator Maisto International, Inc.
909-357-7988 ext.360 909-357-9958 fax (e-mail address removed) www.maisto.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top