У меня есть приложение WinForms, написанное на C# с .NET 3.5. Он выполняет длительный пакетный процесс. Я хочу, чтобы приложение обновляло статус того, что делает пакетный процесс. Каков наилучший способ обновления пользовательского интерфейса?Как я могу получить доступ к потоку пользовательского интерфейса для обновления пользовательского интерфейса при выполнении пакетной обработки в приложении WinForm?
ответ
BackgroundWorker звучит как объект, который вы хотите.
Приложение.DoEvents() или возможно запустить партию в отдельной теме?
Используйте компонент backgroundworker для запуска пакетной обработки в отдельном потоке, это не повлияет на поток пользовательского интерфейса.
Запустите длительный процесс на фоне потока. Класс рабочего рабочего - это простой способ сделать это - он обеспечивает простую поддержку для отправки обновлений прогресса и событий завершения, для которых обработчики событий вызываются в правильном потоке для вас. Это делает код чистым и кратким.
Для отображения обновлений, индикаторы выполнения или текст строки состояния являются двумя наиболее распространенными подходами.
Главное, чтобы помнить, если вы делаете вещи в фоновом потоке, вы должны переключиться в поток пользовательского интерфейса для того, чтобы обновить элементы управления окном и т.д.
Быстрый и грязный способ использует Application.DoEvents()
Но это может вызывают проблемы с событиями заказа. Так что не рекомендуется
Проблема, вероятно, заключается не в том, что вы должны уступить нити ui, но что вы делаете обработку в потоке ui, блокируя ее от обработки сообщений. Вы можете использовать компонент backgroundworker для выполнения пакетной обработки в другом потоке без блокировки потока пользовательского интерфейса.
DoEvents() был тем, что я искал, но я также голосовал за ответы на фоне работы, потому что это похоже на хорошее решение, которое я буду исследовать еще.
Я хочу повторить то, что отмечали мои предыдущие комментаторы: пожалуйста, избегайте DoEvents(), когда это возможно, поскольку это почти всегда форма «взлома» и вызывает кошмары для обслуживания.
Если вы идете по дороге BackgroundWorker (что я предлагаю), вам придется иметь дело с перекрестными вызовами пользовательского интерфейса, если вы хотите вызвать какие-либо методы или свойства элементов управления, поскольку они являются нито-аффинными и должны вызывается только из потока, на котором они были созданы. Используйте Control.Invoke() и/или Control.BeginInvoke(), если это необходимо.
Если вы работаете в фоновом/рабочем потоке, вы можете вызвать Control.Invoke
на одном из элементов управления пользовательского интерфейса, чтобы запустить делегат в потоке пользовательского интерфейса.
Control.Invoke
является синхронным (ожидает, пока делегат не вернется). Если вы не хотите ждать, вы используете .BeginInvoke()
только в очереди команды.
Значение return .BeginInvoke()
позволяет проверить, завершен ли метод или подождать, пока он завершен.
Чтобы узнать, что говорят люди о DoEvents, расскажите, что может случиться.
Скажите, что у вас есть какая-то форма с данными на нем, а ваше долгое время - сохранение базы данных или создание отчета на ее основе. Вы начинаете сохранять или генерировать отчет, а затем периодически вызываете DoEvents, чтобы экран продолжал рисовать.
К сожалению, экран не просто рисует, но также реагирует на действия пользователя. Это происходит потому, что DoEvents останавливает то, что вы сейчас делаете, чтобы обрабатывать все сообщения Windows, ожидающие обработки вашим приложением Winforms. Эти сообщения включают запросы на перерисовку, а также любой пользовательский ввод, щелчок и т. Д.
Так, например, пока вы сохраняете данные, пользователь может делать что-то вроде того, что приложение показывает модальное диалоговое окно, которое полностью не связанный с долговременной задачей (например, Help-> About). Теперь вы реагируете на новые действия пользователя внутри уже запущенной задачи. DoEvents вернется, когда все события, ожидающие, когда вы его вызвали, будут завершены, а затем ваша долговременная задача будет продолжена.
Что делать, если пользователь не закрывает модальный диалог? Ваша долго работающая задача ждет вечно, пока это диалоговое окно не будет закрыто. Если вы совершаете транзакцию в базу данных и выполняете транзакцию, теперь вы держите транзакцию открытой, пока у пользователя есть кофе. Либо ваша транзакция заканчивается, и вы теряете работу настойчивости, либо транзакция не отключается, и вы потенциально блокируете других пользователей БД.
Что здесь происходит, так это то, что Application.DoEvents делает ваш код реентерабельным. См. Определение википедии here. Обратите внимание на некоторые пункты из верхней части статьи, что для того, чтобы код был реентерабельным, он:
- Не должен содержать статических (или глобальных) данных, не являющихся постоянными.
- Должен работать только с данными, предоставленными ему вызывающим абонентом.
- Нельзя полагаться на блокировки для ресурсов однопользовательского режима.
- Нельзя вызывать нерентабельные компьютерные программы или подпрограммы.
Это очень маловероятно, что долго работает код в приложении WinForms работает только на данных, передаваемых методу вызываемого абонента, не имеет статические данные, не держит замков, и вызывает только другие реентрантные методы.
Как многие люди здесь говорят, DoEvents может привести к очень странным сценариям в коде. Ошибки, которые могут привести к этому, могут быть очень трудными для диагностики, и ваш пользователь вряд ли скажет вам: «О, это могло произойти, потому что я щелкнул эту несвязанную кнопку, пока я ждал ее сохранения».
Использование Backgroundworker
, и если вы также пытаетесь обновить GUI нити путем обработки ProgressChanged
события (например, для ProgressBar
), не забудьте также установить WorkerReportsProgress=true
или нить, докладывает прогресс будет умирать в первый раз он пытается позвонить ReportProgress
...
исключение вызывается, но вы можете его не увидеть, если только вы не включили «когда бросили», и на выходе будет показано, что поток вышел.
- 1. WP7 - доступ к потоку пользовательского интерфейса?
- 2. Как получить доступ к потоку пользовательского интерфейса в C#
- 3. Как получить доступ к рабочему потоку из потока пользовательского интерфейса?
- 4. Как получить доступ к потоку пользовательского интерфейса, обрабатываемому на C#?
- 5. Ждите по потоку для активности пользовательского интерфейса
- 6. Обновления пользовательского интерфейса Meteor.js?
- 7. Доступ к потоку пользовательского интерфейса из Socket AsyncCallback
- 8. Обеспечение интерфейса обновления в потоке пользовательского интерфейса
- 9. Общий подход AsyncTask мешает потоку пользовательского интерфейса
- 10. Обновление интерфейса пользовательского интерфейса при выполнении операции меню
- 11. Многопоточность для пользовательского интерфейса WinForm/C#
- 12. Ожидание вызова async WCF не возвращается к потоку пользовательского интерфейса и/или блокирует поток пользовательского интерфейса
- 13. Пауза после обновления пользовательского интерфейса
- 14. Обновление пользовательского интерфейса при выполнении задачи
- 15. Доступ к текстовой легенде интерфейса пользовательского интерфейса, отсортированный как номер
- 16. несколько экземпляров пользовательского интерфейса в winform
- 17. Метод обновления общего пользовательского интерфейса
- 18. Упорядочить последовательность обработки пользовательского интерфейса
- 19. Как вернуться к потоку пользовательского интерфейса после асинхронной операции
- 20. Разрешить обновления пользовательского интерфейса IOS
- 21. QProcess предотвращает обновления пользовательского интерфейса
- 22. Событие FileSystemWatcher OnChanged должно присоединяться к потоку пользовательского интерфейса
- 23. notifyDataSetChanged() без обновления пользовательского интерфейса?
- 24. Как получить доступ к элементам пользовательского интерфейса класса, унаследованного от пользовательского интерфейса View in viewController
- 25. Использование AsyncTask onProgressUpdate для обновления пользовательского интерфейса
- 26. доступ к элементам пользовательского интерфейса с задачей
- 27. Поддерживает ли привязка привязки всегда к потоку пользовательского интерфейса?
- 28. NSStatusItem Blocks Обновления пользовательского интерфейса в NSWindows
- 29. Изменяет ли привязка данных привязки WPF к потоку пользовательского интерфейса?
- 30. Запуск фоновой задачи с доступом к потоку пользовательского интерфейса
Я бы использовал BackgroundWorker и выполнял пакетный запуск в отдельном потоке. Мне не нравится Application.DoEvents(), потому что, даже если вы это делаете, в то время как вы этого не делаете, и вы работаете с обработкой, ваш пользовательский интерфейс полностью не отвечает на запросы и может появиться «подвешен» вашему пользователю. – 2008-09-20 04:34:33
Не делайте этого - это настоящий запах кода. Я никогда не видел «Application.DoEvents()» в производственном коде, где я думал: «Это было самое простое и правильное решение». – 2010-01-11 17:58:38
Если вы используете CLR Profiler 2.0, вы заметите, что использование DoEvents создаст много ручек, которые будут придерживаться! Я бы предложил использовать BackgroundWorker, как сказал jolson. – joek1975 2010-01-21 15:46:54