синхронизировать индикатор выполнения «заполнить» с сообщением о завершении в c # - PullRequest
3 голосов
/ 26 октября 2011

У меня есть Thread , обрабатывающий двоичный файл и сохраняющий его в виде данных. Во время обработки я обновляю индикатор выполнения с текущей позицией потока. Моя проблема в том, в Thread у меня есть блок finally {}, и в этом я устанавливаю значение индикатора выполнения на максимально допустимое значение, затем я запускаю Application.DoEvents();, затем я отображаю MessageBox, но мой MessageBox всегда появляется до того, как Прогрессбар заполняется.

problem

вот соответствующий код

вот видео, показывающее проблему

Я создал небольшое приложение для демонстрации использования BackgroundWorker вместо Thread. Вот код

Я вижу ту же самую «ошибку» (я не решаюсь назвать это ошибкой, скорее, проблемой юзабилити). Как вы можете видеть, я также добавил туда dirty маленький регистратор. Вывод в конце файла журнала:

27.10.2011 16:58:29 - прогресс достигнут

27.10.2011 16:58:29 - Прогресс изменен на 79661

27.10.2011 16:58:29 - Достигнут прогресс

27.10.2011 16:58:29 - Прогресс изменен на 79661

27.10.2011 16:58:29 - Введено

27.10.2011 16:58:29 - События завершены

27.10.2011 16:58:30 - Показано сообщение

Таким образом, нет проблемы с порядком, в котором выполняются команды ... мое единственное реальное решение - добавить задержку перед отображением окна сообщения?

Ответы [ 2 ]

5 голосов
/ 26 октября 2011

Я бы попробовал заменить Application.DoEvents(); на простой Thread.Sleep(100). Документация вокруг DoEvents, похоже, не указывает, разрешено ли вам вызывать ее из другого потока, не являющегося пользовательским интерфейсом. Используя вместо этого Thread.Sleep, вы задерживаете всплывающее окно сообщения и позволяете потоку пользовательского интерфейса нормально обрабатываться.

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

На самом деле, если вы хотите, вы, возможно, могли бы переписать свой код потока, чтобы использовать объект BackgroundWorker , и подписаться на события ProgressChanged и RunWorkerCompleted. Ваш фактический код потока будет отвечать за вызов метода ReportProgress для запуска события ProgressChanged для обновления индикатора выполнения.

Ответ на обновление

Посмотрев на ваш новый код, вы никогда не установите максимальное значение индикатора выполнения после завершения работы. В worker_RunWorkerCompleted добавьте progressBar1.Value = progressBar1.Maximum; перед отображением окна сообщения. Это должно обновить индикатор выполнения до максимума, прежде чем появится окно сообщения.

2 голосов
/ 26 октября 2011

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

Вы также можете вызвать метод в основном потоке пользовательского интерфейса из вторичного потока с помощью ThreadDispatcher (может быть только WPF) или с помощью метода Invoke() в форме.

Редактировать Другое решение - создать собственную форму, похожую на MessageBox, а затем просто сделать так, чтобы это окно отображалось нормально, чтобы оно не блокировало поток пользовательского интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...