Здесь идут две ссылки, пытаясь объяснить, как это работает: (1)(2)
Теперь, я попытаюсь объяснить, как в ближайшее время, как я могу. Большинство из того, что происходит внутри приложения Windows Form, происходит в одном потоке, обычно выполняется один и тот же поток Main(). Если вы откроете Program.cs, вы увидите, что Main() имеет строку, которая выглядит следующим образом:
Application.Run(new Form1());
Если вы отлаживаете приложение в любой момент и проверяете стек вызовов, вы увидите, что он вернется к этому методу Run. Это означает, что приложение Windows Forms на самом деле является непрерывным запуском метода Run. Итак, что делает Run? Run запускает очередь сообщений, через которые Windows отправляет ей сообщения. Затем они отправляют эти сообщения в правильные элементы управления, которые сами выполняют такие вещи, как добавление текста, который соответствует нажатой клавише, перерисовывают себя и т. Д. Обратите внимание, что все это происходит во время и бесконечный цикл, идущий рядом с одним потоком, так что погода вы печатаете или просто перемещая окно вокруг, грузы этих сообщений передаются в приложение, которое, в свою очередь, обрабатывает их и реагирует соответственно, все в одном потоке. Элементы управления также могут отправлять сообщения в очередь через очередь, и даже вы можете размещать сообщения в насосе через Control.BeginInvoke. Одна из вещей, которую эти средства управления делают, - это поднять события в соответствии с тем, что происходит. Таким образом, если вы нажмете кнопку, код, который вы написали для обработки этого клика, в конечном счете и косвенно будет запущен методом Application.Run.
Теперь, что происходит с вашим кодом, так это то, что, хотя вы меняете видимый статус вашего индикатора выполнения на видимый, а затем обновляете его значение, вы меняете его видимость на false, все в одном методе. Это означает, что только после того, как вы покинете метод, Application.Run() сможет продолжить итерацию и потребление очереди сообщений, эффективно попросив индикатор выполнения обновить его отображение. Когда это произойдет, вы уже оставили видимость индикатора выполнения на false, последнее, что вы сделали до выхода из метода. DoEvents() - это быстрый и грязный обходной путь к вашей проблеме, поскольку он читает сообщения в очереди и обрабатывает их. Я действительно не чувствую себя комфортно, используя его, так как он может вызвать проблемы с появлением.
Использование потоков является хорошим решением, но я бы рекомендовал использовать ThreadPool-поток вместо пользовательского потока в подобной ситуации, поскольку я склонен использовать пользовательские потоки только в тех случаях, когда у меня ограниченное число длинноволновых потоков и мне нужно контролировать их жизненные циклы. Самый простой и практичный способ использования потоков - использовать компонент BackgroundWorker, хотя я бы рекомендовал понять, как делать многопоточность Windows Forms с делегатами, если вы хотите действительно понять, что происходит.
Предполагаете, вы рекомендуете перемещать длительный процесс в отдельный поток, чтобы поддерживать постоянный пользовательский интерфейс? –
Да - это то, что помогает BackgroundWorker. –
Цените помощь. Я надеялся избежать потоков, поскольку они довольно сложны вручную, и это простой пользовательский интерфейс, но это звучит прекрасно. Благодарю. –