Остановка функции, выполняемой при нажатии кнопки winform

  1. В простом приложении winform я вызываю функцию, которая бесконечно создает файлы при нажатии кнопки. Я добавляю в цикл Application.DoEvents ().

  2. Я нажимаю красный крестик, чтобы закрыть форму.

  3. форма закрывается, но файлы продолжают создаваться ...

Я думаю, что это тема кнопок, но разве она не должна быть фоновой? попытка изменить Thread.CurrentThread.IsBackGround на True в функции цикла не помогает.

Идеи?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
4 810
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Тот факт, что вы используете Application.DoEvents, является первым признаком проблемы: он показывает, что вы слишком много делаете в потоке пользовательского интерфейса. Это почти никогда не уместно в хорошо структурированной программе. Поток пользовательского интерфейса не предназначен для выполнения каких-либо длительных задач. (По общему признанию, если создание пользовательского интерфейса занимает много времени, у вас мало выбора, но это предполагает, что вам следует упростить пользовательский интерфейс ... и я подозреваю, что в данном случае это неприменимо.)

Вместо этого вы должны выполнять длительную задачу (создание файлов) в отдельном потоке. Справочная информация идеально подходит для этого - вы можете использовать его, чтобы сообщать о прогрессе обратно в пользовательский интерфейс, а пользовательский интерфейс может вызвать метод CancelAsync, чтобы запросить его остановку. Вам нужно проверить свойство CancellationPending внутри рабочего потока, чтобы узнать, была ли запрошена отмена, и остановиться соответствующим образом.

Обновлено: Просто чтобы прояснить, что, как я считаю, происходит - я подозреваю, что ваша форма закрывается, но программа не завершится, пока цикл событий не завершится. Вы поддерживаете цикл событий вместе с циклом создания файла, отсюда и проблема.

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

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

gil 03.11.2008 22:52

Помогло ли мое редактирование? В основном, пока вы не дадите обработчику нажатия кнопки закончить работу, приложение не остановится (если вы не используете что-то ужасное, например Thread.Abort)

Jon Skeet 03.11.2008 22:54

Хорошо, еще один вопрос, вы сказали: «Обратите внимание, что нет потока для кнопки - есть только один для всего вашего пользовательского интерфейса» :: когда я нажимаю красный X, отладчик переходит к удалению. на каком потоке это делается? поскольку пользовательский интерфейс занят зацикливанием ...

gil 03.11.2008 23:01

Он находится в потоке пользовательского интерфейса - посмотрите на стек, и вы увидите, что ваш цикл создания файла также находится там - вызов Application.DoEvents в конечном итоге обработает щелчок X и, следовательно, закрытие формы. Это все в одном потоке - что неприятно, поэтому рекомендуется избегать этого :)

Jon Skeet 03.11.2008 23:03

Джон, ты действительно живешь на ТАК? Ваши ответы читаются так, как если бы вы писали их для книги, все в течение 2-3 минут с момента, когда кто-то задает вопрос. Невероятный.

Alan 03.11.2008 23:06

(... и это должно быть позитивным, без ругательств или цинизма :)

Alan 03.11.2008 23:08

@Alan: Думаю, я слишком часто нажимаю кнопку "Обновить" ... но я занимаюсь и другими делами. Пришло время, например, немного поиграть в Mario Kart ...

Jon Skeet 03.11.2008 23:09

Вы специально создали новый поток для этого кода ButtonClick? Если нет, то он находится в том же потоке, что и форма, поэтому кнопка «X» должен останавливает его.

В любом случае вы можете установить флаг (isClosing) и проверить наличие этого флага в цикле «while true».

Нет, это не должно останавливать его - потому что у вас все еще работает цикл.

Jon Skeet 03.11.2008 22:54

@ Тимоти: Как вы ожидаете, что кнопка X остановит его? В какой-то момент в стеке потока пользовательского интерфейса у нас есть бесконечный цикл. Как будет раскручиваться этот стек? Это должно произойти либо из-за возврата этого обработчика, либо из-за исключения. Почему должно быть выброшено исключение?

Jon Skeet 03.11.2008 22:55

Вы пробовали вызвать на Thread.CurrentThread.Abort()? Это не рекомендуемый способ, но если у вас нет доступа к функции s source code it might help (even though you say you are callingDoEvents` из функции).

Если у вас есть доступ к исходному коду, вы можете поставить там отметку, чтобы цикл знал, что он должен остановиться.

Кроме того, вы можете использовать компонент background worker или создать другой поток и управлять им извне (то есть из формы).

Вызов Thread.Abort почти всегда является неправильным решением, как и вызов Application.DoEvents. Лучше избавиться от последнего, чем добавить первое ...

Jon Skeet 03.11.2008 22:47

Обработчик нажатия кнопки выполняется в потоке пользовательского интерфейса.

Когда вы вызываете Application.DoEvents, вы позволяете потоку пользовательского интерфейса обрабатывать сообщения окна. Одним из следствий этого является то, что каждый раз, когда ваш пользователь нажимает эту кнопку, новый «экземпляр» (кадр стека) метода обработчика кликов вместе с множеством других кадров стека добавляется в стек. Нравится:

{windows forms methods incl. message pump}
  **ClickHandler**
    Application.DoEvents
     {windows forms methods incl. message pump}
      **ClickHandler**
       Application.DoEvents
        {windows forms methods incl. message pump}
          etc.

Все это ужасно.

Если вы хотите запускать код в фоновом режиме, лучше использовать

  • Компонент BackgroundWorker.
  • Стандартный механизм .NET на основе делегатов (BeginInvoke, EndInvoke, IAsyncResult и т. д.) Для запуска кода в пуле потоков.
  • Если вы хотите реализовать длительный фоновый поток, а не передавать «кусок работы» пулу, вы можете создать и запустить поток, который настроен как фоновый поток.

Добавьте эту переменную уровня формы в код вашей формы:

private bool _StillOpen = true;

Затем оберните код бесконечного цикла при нажатии кнопки следующим образом:

while (_StillOpen)
{
    // do whatever your method does
    Application.DoEvents();
}

Наконец, добавьте этот код в событие FormClosing вашей формы:

_StillOpen = false;

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

Другие вопросы по теме