У меня есть простой цикл C# foreach, как я могу выйти из цикла при нажатии кнопки? Это не в фоновом режимеWorker, поэтому я не могу использовать backgroundWorker.CancellationPending.C# Выход из цикла на кнопке
ответ
Создать булевский флаг в форме. Прикрепите обработчик события к событию щелчка кнопок и установите флаг в true в обработчике событий.
Проверьте флаг в цикле, и если это правда, вызовите «break». (Лучшим вариантом было бы использовать цикл while вместо цикла for с проверкой флага в состоянии while)
Очевидно, цикл for должен быть в какой-то форме фоновой нити, иначе GUI выиграл ' t быть отзывчивым. Если вы не знаете, как это сделать, проверьте либо ThreadPool.QueueUserWorkItem, либо BackgroundWorker. Если вы используете BackgroundWorker, вы можете использовать встроенный метод CancelAsync() вместо кодирования собственного флага отмены.
[Изменить: Как указано другими (см. Ниже) и обсуждены более подробно here и here; вам необходимо либо замок, прежде чем получить доступ к BOOL или пометить его как летучий]
[Не забудьте установить правильное состояние флага перед началом цикла.]
Очевидно, что флаг должен быть изменчивым, или доступ должен быть синхронизирован. – EFraim
efraim, зачем вам синхронизировать доступ к простому полю bool? Пользователь не может очень хорошо нажать кнопку, которая запускает цикл, и кнопку, которая отменяет ее одновременно, не так ли? –
@EFraim. Я не уверен в этом. Я не думаю, что вам нужно заблокировать его, потому что вы только записываете его с одного места (событие нажатия кнопки). Цикл for только считывает его, поэтому даже если чтение и запись произошли в одно и то же время, худший случай заключается в том, что ему просто нужно выполнить еще одну итерацию цикла, прежде чем она остановится. Может ли кто-нибудь подтвердить это? –
Вот not- так хорошее решение.
Звоните Application.DoEvents()
на каждой итерации вашей петли. В Button-Click установите переменную в True и в цикле проверьте эту переменную. Если это так, продолжайте разрыв.
Как я уже сказал, это не очень хорошее решение. Application.DoEvents()
может быть очень опасным. Лучший вариант здесь - иметь фоновый поток.
Согласен. Это не очень хорошее решение. Не используйте DoEvents. Положите цикл for на фоновый поток правильно, используя фона рабочего или ThreadPool.QueueUserWorkItem() –
+1 для чего-то, что действительно работает, даже если это довольно уродливое решение, которое не масштабируется ... Вы можете добавить счетчик к нему и вызовите DoEvents каждую n-ю итерацию, чтобы снизить производительность. – Guffa
Вы можете использовать DoEvents, как предложил Аамир, в качестве быстрого исправления.
Для более масштабируемого и поддерживаемого решения вам необходимо переместить работу в отдельный поток. Тогда довольно тривиально, чтобы событие нажатия кнопки установило флаг, чтобы остановить цикл. С другой стороны, есть немного больше работы, чтобы передать результат обратно в поток пользовательского интерфейса.
Используется ли петля foreach для отдельной резьбы? или в потоке пользовательского интерфейса? – ThePower
Является ли цикл запущенным в другой ветке вообще? – AaronLS
Если цикл находится в потоке пользовательского интерфейса, то обработчик события нажатия кнопки не будет достигнут, пока функция, содержащая цикл, не будет завершена. – ThePower