4

I am using VB.NET and I have:

  • a Start button
  • a Stop button
  • a While loop

When the Start button is pressed, the While loop begins. I want to stop the loop when the Stop button is pressed.

I had tried to use Applications.DoEvents, but the loop stops when the Stop button is pressed twice.

Below is my code using Applications.DoEvents

Dim stopclick As Boolean = False

Private Sub btnPlay_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPlay.Click
    btnForward.Enabled = False
    btnStop.Enabled = True
    While 
        ' Perform the while statements
        If stopclick = True Then
            stopclick = False
            Application.DoEvents()
            Exit While
        End If
    End While
End Sub

Private Sub btnStop_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStop.Click
    stopClick = True
End Sub
  1. Have I used Application.DoEvents incorrectly?
  2. What are the other options besides Application.DoEvents? How can I stop the loop with a single Stop button click?

4 Answers 4

5

You need to put the call to Application.DoEvents outside of your If statement, like this:

While True
    Application.DoEvents()
    ' Perform the while statements
    If stopclick Then
        stopclick = False
        Exit While
    End If
End While

The Stop_Click won't have a chance to be processed until you call DoEvents, so, with the way you had it, stopClick would never get set to True.

However, the larger issue, here, is that calling DoEvents, at all, is very bad practice and can lead to some very difficult-to-fix bugs if you aren't very careful. It would be far better if the loop was performed in a background thread. Check out the BackgroundWorker component for an easy to implement threading mechanism for WinForm projects. You'll find it in the tool box of your form designer.

Here's an example of how to do it with the BackgroundWorker component:

Dim stopclick As Boolean = False

Private Sub btnPlay_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPlay.Click
    btnForward.Enabled = False
    btnStop.Enabled = True
    BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub btnStop_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStop.Click
    stopClick = True
End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    stopClick = False
    While Not stopClick
        ' Perform the while statements
    End While
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    btnForward.Enabled = True
    btnStop.Enabled = False
End Sub
Sign up to request clarification or add additional context in comments.

4 Comments

I have tried placing Application.DoEvents() outside of If statement. However, I still have to double click the stop button. 1) How to made the 'Stop button' to be single-clicked to break the loop? 2) Do you know a loop-breaking sample using BackgroundWorker?
Yeah, I just tested it and got the same behavior. I'm not sure why that is, but in any case, it's not the right way to do it anyway, so I wouldn't waste time trying to figure it out. I added an example with the BackgroundWorker.
Dear @Steven Doggart, thank you for your code above. I had tested it, however I got an error. In the while statement, I have a variable ChartControl1 from Form1. When the code runs, it shows an error: "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on." Here are sample of lines in the While statement: ChartControl1.Series.Add(series3) Me.Controls.Add(ChartControl1). The error message shows up at the Me.Controls.Add(ChartControl1)
That is correct. You cannot access any UI elements (e.g. controls, forms) from the background thread. As I said in my other comment on Luke's answer, you need to separate you data model and business logic from your UI so that doing it from a separate thread is possible without touching any controls. If, however, you really need to access a control, you can do it by invoking back to the main thread with the form's Invoke method. For instance: Invoke(Sub() ChartControl1.Series.Add(series3)).
0

You can simplify your while loop significantly by using stopClick as your condition:

While Not stopClick
  Application.DoEvents()
End While

3 Comments

This code snippet worked fine for me - I did execute a bit of code in the loop. I disagree about Application.DoEvents comment above. I have found dealing with multiple threads/background worker is far more error prone and harder to debug/maintain.
@rheitzman While I agree that this code is easy to write and maintain, there is something to be said for a multi-threaded application--especially when a UI is involved. Running your code in a single thread will block the UI. This will be fine for small applications, but for any sort of scalability, a multi-threaded approach is necessary.
@rheitzman If using the BackgroundWorker is too difficult, it's probably because you have not properly separated your business logic and your data model from your UI logic. As long as you have designed your code well, it should be quite trivial. The key thing to note is that you cannot access the UI from the background thread. Therefore, you need to prepare the data, off the UI, before calling the thread, and then update the UI from the results, after the fact. If you really need to access the UI directly, you can always use Invoke, but ideally you won't need to.
-1

I know this is an old thread, but I found a simple workaround. Add a CheckBox to the form (it can even be "off the side of the form," if that made sense).

 Private Sub btnStopLoop_Click(sender As System.Object, e As System.EventArgs) Handles btnStopLoop.Click

    chkEndLoop.CheckState = CheckState.Checked

 End Sub

Then, in the Loop you wish to exit:

 Do Until chkEndLoop.CheckState = CheckState.Checked

   'Do Stuff Here

 Loop

As long as the CheckBox.CheckState = CheckState.Unchecked, the Loop will continue, but when the CheckBox becomes Checked, the Loop will Exit

Comments

-2

You have to use btnstop.focus() at the start of the loop. This will be sure to solve your problem.

Example:

Dim stopclick As Boolean = False

Private Sub btnPlay_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPlay.Click
    btnForward.Enabled = False
    btnStop.Enabled = True
    btnStop.Focus()  ' new code---------------------
    While 
        ' Perform the while statements
        If stopclick = True Then
            stopclick = False
            Application.DoEvents()
            Exit While
        End If
    End While
End Sub

Private Sub btnStop_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStop.Click
    stopClick = True
End Sub

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.