2013-08-20 3 views
3

Я использую VB.NET и у меня есть:Как разорвать петлю с одной кнопкой мыши

  • Start кнопку
  • Stop кнопку
  • While петля

Когда нажата кнопка Start, начинается цикл While. Я хочу остановить цикл, когда нажата кнопка Stop.

Я пытался использовать Applications.DoEvents, но цикл останавливается, когда кнопка Stop нажата дважды.

Ниже мой код, используя 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. ли я Application.DoEvents неправильно?
  2. Каковы другие варианты, кроме Application.DoEvents? Как я могу остановить цикл одним нажатием кнопки Stop?

ответ

2

Вы должны поместить вызов Application.DoEvents вне вашего If заявления, как это:

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

Stop_Click не будет иметь шанс быть обработан, пока вы не вызовете DoEvents, так, с путь у вас был, stopClick никогда не будет установлен в True.

Однако, большая проблема здесь заключается в том, что вызов DoEvents, вообще говоря, очень плохая практика и может привести к некоторым очень трудным для исправления ошибкам, если вы не очень осторожны. Было бы намного лучше, если бы цикл выполнялся в фоновом потоке. Ознакомьтесь с компонентом BackgroundWorker для простого в использовании механизма Threading для проектов WinForm. Вы найдете его в панели инструментов вашего дизайнера форм.

Вот пример того, как сделать это с BackgroundWorker компонента:

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 
+0

Я попытался размещения Application.DoEvents() вне заявления If. Однако мне еще нужно дважды щелкнуть кнопку остановки. 1) Как сделать кнопку «Стоп» одним щелчком, чтобы разбить цикл? 2) Знаете ли вы образец, обрезающий петлю, с помощью BackgroundWorker? – user2150279

+0

Да, я просто проверил его и получил то же поведение. Я не знаю, почему это так, но в любом случае, это не правильный способ сделать это в любом случае, поэтому я не буду тратить время на то, чтобы понять это. Я добавил пример с BackgroundWorker. –

+0

Уважаемый @Steven Doggart, спасибо за ваш код выше. Я проверил его, однако у меня появилась ошибка. В выражении while у меня есть переменная _ChartControl1_ из Form1. Когда код запускается, он показывает ошибку: «Неверная операция кросс-потока: Control 'Form1' обращается из потока, отличного от потока, в котором он был создан." Вот пример строк в инструкции While: 'ChartControl1.Series.Add (series3) Me.Controls.Add (ChartControl1)'. Сообщение об ошибке появляется в 'Me.Controls.Add (ChartControl1)' – user2150279

0

Вы можете упростить свой цикл и значительно используя stopClick в качестве условия:

While Not stopClick 
    Application.DoEvents() 
End While 
+0

Этот фрагмент кода отлично работал для меня - я выполнил немного кода в цикле. Я не согласен с комментарием Application.DoEvents выше. Я нашел, что работа с несколькими потоками/фоновым рабочим гораздо более подвержена ошибкам и сложнее отлаживать/поддерживать. – rheitzman

+1

@ rheitzman Хотя я согласен с тем, что этот код легко писать и поддерживать, есть что сказать для многопоточного приложения - особенно при использовании интерфейса. Выполнение кода в одном потоке блокирует пользовательский интерфейс. Это будет хорошо для небольших приложений, но для любой масштабируемости необходим многопоточный подход. –

+0

@ rheitzman Если использовать «BackgroundWorker» слишком сложно, это, вероятно, из-за того, что вы не отделили свою бизнес-логику и вашу модель данных от логики пользовательского интерфейса. Пока вы хорошо разработали свой код, это должно быть довольно тривиально. Главное отметить, что вы не можете получить доступ к пользовательскому интерфейсу из фонового потока. Поэтому вам необходимо подготовить данные, начиная с пользовательского интерфейса, до вызова потока, а затем обновить пользовательский интерфейс из результатов, после факта. Если вам действительно необходим прямой доступ к пользовательскому интерфейсу, вы всегда можете использовать 'Invoke', но в идеале вам не нужно. –

0

Я знаю, что это но я нашел простое обходное решение. Добавьте CheckBox в форму (это может быть даже «со стороны формы», если это имеет смысл).

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

    chkEndLoop.CheckState = CheckState.Checked 

End Sub 

Затем в цикле вы хотите выйти:

Do Until chkEndLoop.CheckState = CheckState.Checked 

    'Do Stuff Here 

Loop 

Пока CheckBox.CheckState = CheckState.Unchecked, цикл будет продолжаться, но когда галочка Проверил, цикл Выход

-1

Вы должны использовать btnstop.focus() в начале цикла.Это обязательно поможет решить вашу проблему.

Пример:

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