Как обрабатывать обновления управления во время обработки? - PullRequest
2 голосов
/ 09 февраля 2012

Я пишу небольшое приложение .NET (Windows Forms), но мне кажется, что я не могу правильно понять многопоточность.

Приложение имеет очень простую логику: оно отображает основную форму с некоторымипараметры для заполнения, кнопка для запуска обработки и индикатор выполнения;обработка начинается, когда пользователь нажимает на кнопку, индикатор выполнения должен обновляться во время работы программы, некоторые MessageBox могут появляться во время обработки для отображения предупреждений / информации, а когда обработка заканчивается, появляется другое MessageBox срезультаты, достижения.Довольно просто ... но я не могу найти способ правильно обрабатывать обновления управления.

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

В событии обработки кнопок я запустил новый Thread и заставил его выполнятьобработка, а затем вызывается Thread.Join на нем;MSDN documentatin говорит о Thread.Join: «Блокирует вызывающий поток до тех пор, пока поток не прекратит работу, продолжая при этом выполнять стандартную откачку COM и SendMessage» (http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx). Но, похоже, это не так: после вызова Thread.Join форма снова перестала отвечать до тех пор, пока поток не завершился. Почему это так? Я отказался от идеи соединения и сразу же вернулся из функции обработки событий (отключение кнопок на форме, чтобы пользователи не запускали более одной обработки одновременно),но потом я столкнулся с другой проблемой: я начал получать исключения при попытке обновить индикатор выполнения, среда выполнения жаловалась на то, что вызвал элемент управления из потока, который не является его владельцем.

Так что я наконец-то выбрал BackgroundWorker: Я добавил один к форме, назвал его RunWorkerAsync() методом и использовал ReportProgress() для запуска события ProgressChanged и обработки его в основной форме (чтобы избежать проблемы обновления управления несколькими потоками). Я наконец-то смогобновить индикатор выполнения ... но теперь это полностью асинхронно: прогрессПанель s фактически обновляется через некоторый случайный интервал после того, как рабочий поток вызывает ReportProgress() (даже одну секунду!), и это дает особенно ужасный визуальный эффект.Два примера:

  • Если я вызову ReportProgress() из рабочего потока, а затем MessageBox.Show(), чтобы отобразить какое-то сообщение о текущем шаге обработки, я вижу, как индикатор выполнения опережает после выскакивает MessageBox.
  • У меня есть событие RunWorkerCompleted, которое выскакивает последние MessageBox с результатами, и я вижу, как оно появляется на экране , пока индикатор выполнения все еще заполняетсяпоследние шаги .

Что мне здесь не хватает?

Ответы [ 3 ]

0 голосов
/ 09 февраля 2012

добавьте Application.DoEvents () для обновления пользовательского интерфейса там, где это необходимо.

0 голосов
/ 09 февраля 2012

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

Чтобы преодолеть проблему «обновления управления из другого потока», вы можете использовать команды Invoke или BeingInvoke дляконтроль (для этого я использую метод расширения ).

Помимо этого, я думаю, что комментарий Кангкана является законным - использование MessageBox только добавляет боли вашей проблеме, потому что это модально и блокирует обновление пользовательского интерфейса.Вы УВЕРЕНЫ в том, что MessageBox уместен? Вам абсолютно необходим ввод пользователя, прежде чем продолжить?Или вам просто нужно сообщить им?Если последнее, вам следует подумать об использовании чего-то более похожего на строку состояния или системных сообщений, которые вы получаете здесь в StackOverflow (представьте, если бы они все были предупреждениями!)

0 голосов
/ 09 февраля 2012

На мой взгляд, лучший способ справиться с асинхронностью в приложениях WinForm (и WPF) - Reactive Extensions . Немного кривой, чтобы пройти, но как только вы получите его, вы не вернетесь.

...