Korzystanie z aplikacji.DoEvents()

Czy Application.DoEvents() może być używany w C#?

Czy ta funkcja pozwala GUI dogonić resztę aplikacji, w taki sam sposób, jak VB6 DoEvents robi?

Author: Daniel B, 2011-03-03

9 answers

Hmya, the enduring mystique of DoEvents (). Była ogromna ilość luzu przeciwko temu, ale nikt nigdy tak naprawdę nie wyjaśnia, dlaczego jest "zły". Taka sama mądrość jak "nie mutuj struktury". Erm, dlaczego runtime i Język Obsługuje mutowanie struktury, jeśli to jest takie złe? Z tego samego powodu: strzelisz sobie w stopę, jeśli nie zrobisz tego dobrze. Łatwo. A zrobienie tego dobrze wymaga znajomości dokładnie tego, co robi, co w przypadku DoEvents() zdecydowanie nie jest łatwy do grok.

Od razu: prawie każdy program Windows Forms zawiera wywołanie DoEvents (). Jest sprytnie zamaskowany, jednak z inną nazwą: ShowDialog (). Jest to metoda DoEvents (), która umożliwia modalne okno dialogowe bez zamrażania reszty okien w aplikacji.

Większość programistów chce używać DoEvents, aby powstrzymać zamrożenie interfejsu użytkownika podczas pisania własnej pętli modalnej. Na pewno tak robi; wysyła komunikaty Windows i dostaje wszelkie prośby o malowanie dostarczone. Problem jednak polega na tym, że nie jest selektywny. Nie tylko wysyła wiadomości paint, ale także dostarcza wszystko inne.

I jest zestaw powiadomień, które powodują kłopoty. Pochodzą z około 3 stóp przed monitorem. Użytkownik może na przykład zamknąć główne okno, gdy uruchomiona jest pętla wywołująca metodę DoEvents (). To działa, interfejs użytkownika zniknął. Ale twój Kod się nie zatrzymał, nadal wykonuje pętlę. To źle. Bardzo, bardzo źle.

Jest więcej: użytkownik może kliknąć ten sam element menu lub przycisk, który powoduje uruchomienie tej samej pętli. Teraz masz dwie zagnieżdżone pętle wykonujące metodę DoEvents (), poprzednia pętla jest zawieszona, a nowa zaczyna się od zera. To może zadziałać, ale szanse są niewielkie. Szczególnie, gdy zagnieżdżona pętla kończy się, a zawieszona wznawia się, próbując zakończyć zadanie, które zostało już zakończone. Jeśli to nie bomba z wyjątkiem to na pewno dane są szyfrowane wszystko do cholera.

Powrót do ShowDialog (). Wykonuje metodę doevents (), ale należy pamiętać, że robi coś innego. To wyłącza wszystkie okna w aplikacji , inne niż okno dialogowe. Teraz, gdy problem 3 stóp został rozwiązany, użytkownik nie może zrobić nic, aby zepsuć logikę. Zarówno tryb zamykania okna, jak i uruchamiania zadania ponownie zostają rozwiązane. Inaczej mówiąc, nie ma możliwości, aby użytkownik uruchomił kod w innej kolejności. Będzie działać przewidywalnie, tak jak tak było, gdy testowałeś swój kod. To sprawia, że okna dialogowe bardzo irytujące; kto nie nienawidzi mieć aktywne okno dialogowe i nie jest w stanie skopiować i wkleić coś z innego okna? Ale taka jest cena.

Czyli czego potrzeba, aby bezpiecznie używać DoEvents w Twoim kodzie. Ustawienie właściwości Enabled wszystkich formularzy na false to szybki i skuteczny sposób na uniknięcie problemów. Oczywiście żaden programista nie lubi tego robić. I nie. dlatego nie powinieneś używać doevents (). Ty powinien używać wątków. Nawet jeśli dają Ci kompletny arsenał sposobów, aby strzelać stopę w kolorowe i tajemnicze sposoby. Ale z tą zaletą, że strzelasz tylko własną nogą; nie pozwoli (zazwyczaj) użytkownikowi strzelać jej.

Kolejne wersje C # i VB.NET dostarczy inną broń z nowymi słowami kluczowymi oczekuj i asynchronizuj. Zainspirowany w małej części problemami spowodowanymi przez doevents i threads, ale w dużej części przez projekt API WinRT, który wymaga , aby zachować swoje Interfejs użytkownika aktualizowany podczas operacji asynchronicznej. Jak czytanie z pliku.

 427
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-23 10:20:55

Może być, ale to włamanie.

Zobacz Czy DoEvents Jest Złe?.

Bezpośrednio z strony MSDN że thedev odwołuje się:

Wywołanie tej metody powoduje, że bieżący wątek do zawieszenia podczas gdy wszystkie wiadomości oczekujących okien są przetwarzane. Jeśli wiadomość powoduje, że zdarzenie jest wyzwalane, następnie inne obszary twojego kod aplikacji może zostać wykonany. To może spowodować wystawienie wniosku nieoczekiwane zachowania, które są trudne do debugowania. Jeśli wykonujesz operacje lub obliczenia, które biorą długi czas, często lepiej jest wykonać te operacje na nowym nić. Więcej informacji na temat programowanie asynchroniczne, zobacz Przegląd Programowania Asynchronicznego.

Więc Microsoft przestrzega przed jego użyciem.

Również uważam to za hack, ponieważ jego zachowanie jest nieprzewidywalne i podatne na skutki uboczne (wynika to z doświadczenia w próbie użycia DoEvents zamiast kręcenia nowego wątku lub za pomocą workera w tle).

Nie ma tu machismo - gdyby to działało jako solidne rozwiązanie, byłbym wszędzie. Jednak próba użycia DoEvents w. NET sprawiła mi tylko ból.

 27
Author: RQDQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:06

Tak, w klasie aplikacji w systemie istnieje statyczna metoda DoEvents.Okna.Forms namespace. System.Okna.Formularze.Podanie.Doevents () może być użyte do przetworzenia wiadomości oczekujących w kolejce w wątku UI podczas wykonywania długotrwałego zadania w wątku UI. Ma to tę zaletę, że interfejs użytkownika wydaje się bardziej responsywny i nie jest "zablokowany", gdy działa długie zadanie. Jednak prawie zawsze nie jest to najlepszy sposób na robienie rzeczy. Według Microsoftu wywołującego DoEvents "...powoduje zawieszenie bieżącego wątku podczas przetwarzania wszystkich wiadomości oczekujących w oknie."Jeśli zdarzenie zostanie wywołane, istnieje możliwość wystąpienia nieoczekiwanych i przerywanych błędów, które są trudne do wyśledzenia. Jeśli masz rozbudowane zadanie, o wiele lepiej zrobić to w osobnym wątku. Uruchamianie długich zadań w osobnym wątku pozwala na ich przetwarzanie bez ingerencji w płynne działanie interfejsu użytkownika. Zobacz tutaj Po Więcej Szczegółów.

Tutaj {[2] } jest przykład jak używać DoEvents; należy pamiętać, że Microsoft zapewnia również ostrożność przed jego używaniem.

 23
Author: Bill W,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 19:23:02

Z mojego doświadczenia radzę dużą ostrożność przy używaniu DoEvents w .NET. doświadczyłem bardzo dziwnych wyników podczas używania DoEvents w TabControl zawierającym DataGridViews. Z drugiej strony, jeśli masz do czynienia z małym formularzem z paskiem postępu, to może być OK.

Najważniejsze jest to, że jeśli zamierzasz używać DoEvents, musisz dokładnie przetestować go przed wdrożeniem aplikacji.

 14
Author: Craig Johnston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-20 14:54:32

Tak.

Jednakże, jeśli potrzebujesz użyć Application.DoEvents, jest to głównie oznaka złego projektu aplikacji. Może chciałbyś popracować w osobnym wątku?

 10
Author: Frederik Gheysels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-24 13:59:08

Widziałem wiele komercyjnych aplikacji, używających "Doevents-Hack". Szczególnie, gdy rendering wchodzi w grę, często widzę to:

while(running)
{
    Render();
    Application.DoEvents();
}
Wszyscy wiedzą o złu tej metody. Jednak używają hack, ponieważ nie znają żadnego innego rozwiązania. Oto kilka podejść zaczerpniętych z postu na blogu autorstwa Toma Millera:
  • Ustaw formularz tak, aby wszystkie rysunki były wyświetlane w WmPaint i wykonaj tam rendering. Przed końcem OnPaint metoda, upewnij się, że to zrobisz.Invalidate(); spowoduje to ponowne wywołanie metody OnPaint.
  • P / wywołaj do API Win32 i wywołaj PeekMessage / TranslateMessage / DispatchMessage. (Doevents faktycznie robi coś podobnego, ale można to zrobić bez dodatkowych przydziałów).
  • Napisz własną klasę forms, która jest małym opakowaniem wokół CreateWindowEx i daj sobie pełną kontrolę nad pętlą komunikatów. - Zdecydować, że metoda DoEvents działa dobrze dla Ciebie i trzymaj się tego.
 4
Author: Matthias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 21:59:06

Zobaczyłem komentarz jheriko powyżej i początkowo zgodziłem się, że nie mogę znaleźć sposobu, aby uniknąć używania DoEvents, jeśli skończysz kręcąc głównym wątkiem UI czekając na długo działający asynchroniczny fragment kodu w innym wątku. Ale z odpowiedzi Matthiasa proste odświeżenie małego panelu na moim UI może zastąpić DoEvents (i uniknąć nieprzyjemnego efektu ubocznego).

Więcej szczegółów w mojej sprawie ...

Wykonywałem następujące czynności (zgodnie z sugestią tutaj ), aby upewnić się, że pasek postępu Typ ekranu powitalnego (Jak wyświetlić nakładkę "Ładowanie"...) aktualizacja podczas długiego działania polecenia 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
}

Złe: dla mnie wywołanie DoEvents oznaczało, że kliknięcia myszką czasami uruchamiały formularze za moim ekranem powitalnym, nawet jeśli zrobiłem to na najwyższym poziomie.

Dobra / odpowiedź: Zastąp linię DoEvents prostym wywołaniem odświeżania do małego panelu na środku ekranu powitalnego, FormSplash.Panel1.Refresh(). Interfejs aktualizuje się ładnie i dziwność DoEvents inni ostrzegali przed zniknięciem.

 3
Author: TamW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:34

Zastosowanie.DoEvents może powodować problemy, jeśli w kolejce komunikatów znajduje się coś innego niż przetwarzanie grafiki.

Może być przydatny do aktualizacji pasków postępu i powiadamiania Użytkownika o postępach w czymś takim jak budowa i ładowanie MainForm, jeśli zajmie to chwilę.

W niedawnej aplikacji, którą wykonałem, użyłem DoEvents do aktualizacji niektórych etykiet na ekranie ładowania za każdym razem, gdy blok kodu jest wykonywany w konstruktorze mojej formy głównej. Wątek UI był, w tym przypadek, zajęty wysyłaniem wiadomości e-mail na serwerze SMTP, który nie obsługiwał wywołań SendAsync (). Prawdopodobnie mógłbym utworzyć inny wątek z metodami Begin() I End() i wywołać Send() z ich, ale ta metoda jest podatna na błędy i wolałbym, aby główna forma mojej aplikacji nie rzucała WYJĄTKÓW podczas budowy.

 2
Author: Guest123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-20 16:43:52

Sprawdź dokumentację MSDN dla Application.DoEvents metoda.

 2
Author: thedev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-24 13:58:14