Элемент управления индикатора выполнения является объектом пользовательского интерфейса и создается в потоке пользовательского интерфейса. Когда вы вызываете Invoke или BeginInvoke, чтобы обновить его, вы запрашиваете обновление пользовательского интерфейса.
Однако поток пользовательского интерфейса занят - в обработчике события CLick вашей кнопки есть цикл, который Sleep () отслеживает поток и вызывает prog.IncA в цикле. Таким образом, он никогда не возвращается обратно в основной цикл пользовательского интерфейса (который отправляет сообщения Windows и обновляет пользовательский интерфейс). Ваш индикатор выполнения является внутренним обновлением, но у него никогда не будет возможности перерисовать, потому что поток пользовательского интерфейса "занят".
Код «обработки» (то есть зацикливание и вызов prog.IncA ()) вообще не должен выполняться в потоке пользовательского интерфейса - его нужно запустить в отдельном потоке, а затем выйти из обработчика Click, чтобы Пользовательский интерфейс может продолжить обновление.
Обратите внимание, что это имеет побочный эффект - если ваш поток пользовательского интерфейса работает, то пользователь сможет продолжить взаимодействие с вашей программой, и поэтому он может снова нажать на кнопку и запустить другой фоновый поток - так что у вас есть быть очень осторожным, чтобы убедиться, что пользователь не может делать ничего «опасного» в пользовательском интерфейсе, пока вы заняты обработкой.
Я предлагаю вам взглянуть на некоторые учебные пособия по ознакомлению с потоками, чтобы получить представление о том, как использовать BackgroundWorker или другой механизм для запуска кода в отдельном потоке. Как только вы поймете это, вы можете добавить индикатор выполнения. (И обратите внимание, что хотя индикатор выполнения звучит как простейшая вещь, на самом деле это довольно сложно сделать из-за необходимости продолжения работы потока пользовательского интерфейса, но не позволяя пользователю делать что-либо опасное во время вашей обработки)