9 ответов:
Hmya, непреходящая мистика DoEvents (). Там было огромное количество реакции против него, но никто никогда не объясняет, почему это "плохо". Такая же мудрость, как "не мутировать структуру". ЭМ, почему среда выполнения и язык поддерживают мутацию структуры, если это так плохо? По той же причине: вы стреляете себе в ногу, если вы не делаете это правильно. Легко. И делать это правильно требует знания ровно что он делает, что в случае DoEvents () является определенно не легко Грок.
сразу же: почти любая программа Windows Forms на самом деле содержит вызов DoEvents(). Он ловко замаскирован, однако с другим именем: ShowDialog (). Именно DoEvents () позволяет диалогу быть модальным без замораживания остальных окон в приложении.
большинство программистов хотят использовать DoEvents, чтобы остановить их пользовательский интерфейс от замораживания, когда они пишут свой собственный модальный цикл. Он, конечно, делает это; это отправляет сообщения Windows и получает все запросы краски доставлены. Проблема, однако, в том, что он не является избирательным. Он не только отправляет сообщения краски, но и доставляет все остальное.
и там есть набор уведомлений, которые вызывают проблемы. Они приходят от около 3 футов перед монитором. Пользователь может, например, закрыть главное окно во время выполнения цикла, который вызывает DoEvents (). Это работает, пользовательский интерфейс ушел. Но ваш код не остановился, он по-прежнему выполнение цикла. Это плохо. Очень, очень плохо.
есть еще: пользователь может нажать тот же пункт меню или кнопку, которая вызывает тот же цикл, чтобы начать работу. Теперь у вас есть два вложенных цикла, выполняющих DoEvents (), предыдущий цикл приостанавливается и новый цикл начинается с нуля. Это может сработать, но шансы невелики. Особенно, когда вложенный цикл заканчивается и приостановленный возобновляется, пытаясь закончить работу, которая уже была завершена. Если это не бомбит с помощью исключение тогда, конечно, данные скремблированы все в ад.
вернуться к ShowDialog (). Он выполняет DoEvents (), но обратите внимание, что он делает что-то еще. Это отключает все окна в приложении, кроме диалога. Теперь, когда 3-футовая проблема решена, пользователь не может ничего сделать, чтобы испортить логику. Решаются как режимы закрытия окна, так и режимы повторного запуска задания. Или, говоря по-другому, пользователь не может заставить вашу программу запускать код в другом порядке. Он будет выполняться предсказуемо, так же, как и при тестировании кода. Это делает диалоги чрезвычайно раздражающими; кто не ненавидит, когда диалог активен и не может скопировать и вставить что-то из другого окна? Но такова цена.
Что требуется для безопасного использования DoEvents в вашем коде. Установка свойства Enabled для всех ваших форм false-это быстрый и эффективный способ избежать проблем. Конечно, ни один программист никогда не любит делать этот. Именно поэтому вы не должны использовать DoEvents(). Вы должны использовать потоки. Несмотря на то, что они передают вам полный арсенал способов стрелять в ногу красочными и непостижимыми способами. Но с тем преимуществом, что вы стреляете только в свою ногу; это не позволит (как правило) пользователю стрелять в нее.
следующие версии C# и VB.NET предоставит другой пистолет с новыми ключевыми словами await и async. Вдохновленный в малой степени неприятностями, вызванными событиями и потоками, но в большая часть дизайна API WinRT, что требует вы должны обновлять свой пользовательский интерфейс во время асинхронной операции. Как чтение из файла.
Это может быть, но это лайфхак.
посмотреть Функция Doevents-Это Зло?.
прямые от страница MSDN это thedev ссылки:
вызов этого метода вызывает ток нить должна быть приостановлена, пока все сообщения окна ожидания обрабатываются. Если сообщение вызывает событие срабатывает, то другие области вашего код приложения может выполняться. Это может вызывают ваше заявление экспонат неожиданное поведение трудно отлаживать. Если вы выполняете операции или вычисления, которые принимают долгое время, часто предпочтительно к выполните эти операции на новом нитка. Для получения дополнительной информации о асинхронное программирование, см. Обзор Асинхронного Программирования.
поэтому Microsoft предостерегает от его использования.
кроме того, я считаю это взломом, потому что его поведение непредсказуемо и подвержено побочным эффектам (это происходит из опыта попытка использовать DoEvents вместо того, чтобы раскручивать новый поток или использовать фоновый рабочий).
здесь нет мачизма - если бы это работало как надежное решение, я бы все это сделал. Однако попытка использовать DoEvents в .NET не вызвала у меня ничего, кроме боли.
да, в классе приложения в системе есть статический метод DoEvents.Окна.Формирует пространство имен. Система.Окна.Формы.Приложение.DoEvents () может использоваться для обработки сообщений, ожидающих в очереди в потоке пользовательского интерфейса при выполнении длительной задачи в потоке пользовательского интерфейса. Это имеет то преимущество, что пользовательский интерфейс кажется более отзывчивым и не "заблокирован" во время выполнения длительной задачи. Однако это почти всегда не лучший способ сделать что-то. Согласно Microsoft, вызывая DoEvents "...вызывает приостановку текущего потока во время обработки всех сообщений окна ожидания."Если событие запускается, существует вероятность неожиданных и прерывистых ошибок, которые трудно отследить. Если у вас есть обширная задача, гораздо лучше делать это в отдельном потоке. Выполнение длинных задач в отдельном потоке позволяет обрабатывать их без вмешательства в пользовательский интерфейс, продолжая работать гладко. Смотри здесь дополнительные подробности.
здесь является примером того, как использовать DoEvents; обратите внимание, что Microsoft также предостерегает от его использования.
из моего опыта я бы посоветовал большую осторожность с использованием DoEvents в. NET.я испытал некоторые очень странные результаты при использовании DoEvents в TabControl, содержащем DataGridViews. С другой стороны, если все, с чем вы имеете дело, - это небольшая форма с индикатором выполнения, то это может быть нормально.
суть в следующем: если вы собираетесь использовать DoEvents, то вам нужно тщательно протестировать его перед развертыванием приложения.
да.
однако, если вам нужно использовать
Application.DoEvents, Это в основном признак плохого дизайна приложения. Возможно, вы хотели бы сделать некоторую работу в отдельном потоке вместо этого?
Я видел много коммерческих приложений, используя "DoEvents-Hack". Особенно когда рендеринг вступает в игру, я часто вижу это:
while(running) { Render(); Application.DoEvents(); }все они знают о зле этого метода. Однако они используют Хак, потому что они не знают никакого другого решения. Вот некоторые подходы, взятые из блоге by Тома Миллера:
- установите форму, чтобы все чертежи происходили в WmPaint и выполняли рендеринг там. Перед завершением метода OnPaint убедитесь, что вы делаете это.Invalidate (); это приведет к немедленному запуску метода OnPaint.
- P / Invoke в Win32 API и вызов PeekMessage/TranslateMessage/DispatchMessage. (Функция doevents на самом деле делает что-то подобное, но вы можете сделать это без дополнительных ассигнований).
- напишите свой собственный класс форм, который является небольшой оболочкой вокруг CreateWindowEx, и дайте себе полный контроль над циклом сообщений. - Решите, что метод DoEvents отлично работает для вас и придерживаться его.
Я видел комментарий jheriko выше и изначально соглашался с тем, что я не мог найти способ избежать использования DoEvents, если вы в конечном итоге вращаете свой основной поток пользовательского интерфейса, ожидая завершения длинного асинхронного фрагмента кода в другом потоке. Но из ответа Маттиаса простое обновление небольшой панели на моем пользовательском интерфейсе может заменить DoEvents (и избежать неприятного побочного эффекта).
подробнее о моем случае ...
Я делал следующее (Как было предложено здесь) чтобы убедиться, что индикатор выполнения типа заставки (как отобразить наложение "загрузка"...) обновлено во время длительной работы команды SQL:
IAsyncResult asyncResult = sqlCmd.BeginExecuteNonQuery(); while (!asyncResult.IsCompleted) //UI thread needs to Wait for Async SQL command to return { System.Threading.Thread.Sleep(10); Application.DoEvents(); //to make the UI responsive }плохое: для меня вызов DoEvents означал, что щелчки мыши иногда стреляли по формам за моим заставкой, даже если я сделал это самым верхним.
хороший/ответ: замените строку DoEvents простым вызовом обновления на небольшую панель в центре моего экрана-заставки,
FormSplash.Panel1.Refresh(). Пользовательский интерфейс обновляется красиво, и странность DoEvents, о которой предупреждали другие, исчезла.
приложение.DoEvents может создавать проблемы, если в очередь сообщений помещается что-то другое, кроме обработки графики.
Это может быть полезно для обновления прогресс-баров и уведомления Пользователя о прогрессе в чем-то вроде mainform строительства и загрузки, если это займет некоторое время.
в недавнем приложении, которое я сделал, я использовал DoEvents для обновления некоторых меток на экране загрузки каждый раз, когда блок кода выполняется в конструкторе моей основной формы. Поток пользовательского интерфейса в этом случае он был занят отправкой электронной почты на SMTP-сервере, который не поддерживал вызовы SendAsync (). Вероятно, я мог бы создать другой поток с методами Begin() и End() и вызвать Send() из их, но этот метод подвержен ошибкам, и я бы предпочел, чтобы основная форма моего приложения не бросала исключения во время построения.
проверьте документацию MSDN для
Application.DoEventsметод.
Comments