2009-08-03 1 views
2

У меня есть простой цикл C# foreach, как я могу выйти из цикла при нажатии кнопки? Это не в фоновом режимеWorker, поэтому я не могу использовать backgroundWorker.CancellationPending.C# Выход из цикла на кнопке

+1

Используется ли петля foreach для отдельной резьбы? или в потоке пользовательского интерфейса? – ThePower

+0

Является ли цикл запущенным в другой ветке вообще? – AaronLS

+1

Если цикл находится в потоке пользовательского интерфейса, то обработчик события нажатия кнопки не будет достигнут, пока функция, содержащая цикл, не будет завершена. – ThePower

ответ

5

Создать булевский флаг в форме. Прикрепите обработчик события к событию щелчка кнопок и установите флаг в true в обработчике событий.

Проверьте флаг в цикле, и если это правда, вызовите «break». (Лучшим вариантом было бы использовать цикл while вместо цикла for с проверкой флага в состоянии while)

Очевидно, цикл for должен быть в какой-то форме фоновой нити, иначе GUI выиграл ' t быть отзывчивым. Если вы не знаете, как это сделать, проверьте либо ThreadPool.QueueUserWorkItem, либо BackgroundWorker. Если вы используете BackgroundWorker, вы можете использовать встроенный метод CancelAsync() вместо кодирования собственного флага отмены.

[Изменить: Как указано другими (см. Ниже) и обсуждены более подробно here и here; вам необходимо либо замок, прежде чем получить доступ к BOOL или пометить его как летучий]

[Не забудьте установить правильное состояние флага перед началом цикла.]

+4

Очевидно, что флаг должен быть изменчивым, или доступ должен быть синхронизирован. – EFraim

+3

efraim, зачем вам синхронизировать доступ к простому полю bool? Пользователь не может очень хорошо нажать кнопку, которая запускает цикл, и кнопку, которая отменяет ее одновременно, не так ли? –

+0

@EFraim. Я не уверен в этом. Я не думаю, что вам нужно заблокировать его, потому что вы только записываете его с одного места (событие нажатия кнопки). Цикл for только считывает его, поэтому даже если чтение и запись произошли в одно и то же время, худший случай заключается в том, что ему просто нужно выполнить еще одну итерацию цикла, прежде чем она остановится. Может ли кто-нибудь подтвердить это? –

4

Вот not- так хорошее решение.

Звоните Application.DoEvents() на каждой итерации вашей петли. В Button-Click установите переменную в True и в цикле проверьте эту переменную. Если это так, продолжайте разрыв.

Как я уже сказал, это не очень хорошее решение. Application.DoEvents() может быть очень опасным. Лучший вариант здесь - иметь фоновый поток.

+2

Согласен. Это не очень хорошее решение. Не используйте DoEvents. Положите цикл for на фоновый поток правильно, используя фона рабочего или ThreadPool.QueueUserWorkItem() –

+0

+1 для чего-то, что действительно работает, даже если это довольно уродливое решение, которое не масштабируется ... Вы можете добавить счетчик к нему и вызовите DoEvents каждую n-ю итерацию, чтобы снизить производительность. – Guffa

0

Вы можете использовать DoEvents, как предложил Аамир, в качестве быстрого исправления.

Для более масштабируемого и поддерживаемого решения вам необходимо переместить работу в отдельный поток. Тогда довольно тривиально, чтобы событие нажатия кнопки установило флаг, чтобы остановить цикл. С другой стороны, есть немного больше работы, чтобы передать результат обратно в поток пользовательского интерфейса.