W mojej aplikacji nieustannie przechodzę od jednej kontrolki do drugiej. Stworzyłem nie. elementów sterujących użytkownika, ale podczas nawigacji moje elementy sterujące migają. Aktualizacja zajmuje 1 lub 2 sekundy. Próbowałem to ustawić
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
ale to nie pomogło ... Każda kontrolka ma ten sam obraz tła z różnymi kontrolkami. Więc jakie jest na to rozwiązanie…
Dzięki.
c#
winforms
user-controls
flicker
Royson
źródło
źródło
UpdateStyles
po ustawieniu tych? Jest to źle udokumentowane, ale czasami może być konieczne.Odpowiedzi:
Nie jest to rodzaj migotania, który może rozwiązać podwójne buforowanie. Ani BeginUpdate ani SuspendLayout. Masz zbyt wiele kontrolek, obraz BackgroundImage może to znacznie pogorszyć.
Rozpoczyna się, gdy UserControl maluje się. Rysuje BackgroundImage, pozostawiając dziury w miejscach, w których znajdują się okna kontroli dzieci. Każdy element sterujący podrzędny otrzymuje następnie komunikat, aby sam się malował, wypełniając otwór zawartością swojego okna. Kiedy masz dużo kontrolek, te dziury są widoczne dla użytkownika przez chwilę. Zwykle są białe i źle kontrastują z obrazem BackgroundImage, gdy jest ciemno. Lub mogą być czarne, jeśli formularz ma ustawioną właściwość Opacity lub TransparencyKey, źle kontrastując z prawie wszystkim.
Jest to dość fundamentalne ograniczenie Windows Forms, utknęło w sposobie renderowania okien przez Windows. Naprawione przez WPF przy okazji, nie używa okien do kontrolek podrzędnych. To, czego chcesz, to podwójne buforowanie całego formularza, w tym kontrolek podrzędnych. To możliwe, sprawdź mój kod w tym wątku, aby znaleźć rozwiązanie. Ma jednak efekty uboczne i tak naprawdę nie zwiększa szybkości malowania. Kod jest prosty, wklej go w formularzu (nie w kontrolce użytkownika):
Jest wiele rzeczy, które możesz zrobić, aby przyspieszyć malowanie, do tego stopnia, że migotanie nie jest już zauważalne. Zacznij od rozwiązania BackgroundImage. Mogą być naprawdę drogie, gdy obraz źródłowy jest duży i trzeba go zmniejszyć, aby pasował do kontroli. Zmień właściwość BackgroundImageLayout na „Tile”. Jeśli daje to zauważalne przyspieszenie, wróć do programu do malowania i zmień rozmiar obrazu, aby lepiej pasował do typowego rozmiaru elementu sterującego. Lub napisz kod w metodzie OnResize () UC, aby utworzyć kopię obrazu o odpowiednim rozmiarze, tak aby nie trzeba było zmieniać rozmiaru za każdym razem, gdy formant jest malowany. Użyj formatu pikseli Format32bppPArgb dla tej kopii, renderuje ona około 10 razy szybciej niż jakikolwiek inny format pikseli.
Następną rzeczą, którą możesz zrobić, jest zapobieganie takiemu zauważaniu dziur i złemu kontrastowaniu z obrazem. Możesz wyłączyć flagę stylu WS_CLIPCHILDREN dla UC, flagę, która zapobiega malowaniu UC w obszarze, do którego przechodzą kontrolki potomne. Wklej ten kod w kodzie UserControl:
Elementy sterujące podrzędne będą teraz malować się na obrazie tła. Nadal możesz zobaczyć, jak malują się jeden po drugim, ale brzydka pośrednia biała lub czarna dziura nie będzie widoczna.
Wreszcie, zmniejszenie liczby kontroli dzieci jest zawsze dobrym podejściem do rozwiązywania problemów z powolnym malowaniem. Zastąp zdarzenie OnPaint () UC i narysuj to, co jest teraz pokazane w dziecku. Poszczególne etykiety i PictureBox są bardzo marnotrawne. Wygodne do wskazywania i klikania, ale ich lekka alternatywa (rysowanie ciągu znaków lub obrazu) zajmuje tylko jeden wiersz kodu w metodzie OnPaint ().
źródło
To jest prawdziwy problem, a odpowiedź, której udzielił Hans Passant, świetnie nadaje się do oszczędzania migotania. Jednak, jak wspomniał, istnieją efekty uboczne, które mogą być brzydkie (brzydki interfejs użytkownika). Jak wspomniano, „Możesz wyłączyć
WS_CLIPCHILDREN
flagę stylu dla UC”, ale to wyłącza ją tylko dla UC. Komponenty w głównym formularzu nadal mają problemy.Na przykład pasek przewijania panelu nie maluje, ponieważ technicznie znajduje się w obszarze podrzędnym. Jednak komponent podrzędny nie rysuje paska przewijania, więc nie jest malowany, dopóki nie zostanie najechany myszką (lub inne zdarzenie go wyzwoli).
Ponadto animowane ikony (zmiana ikon w pętli oczekiwania) nie działają. Usunięcie ikon na stronie
tabPage.ImageKey
nie zmienia odpowiednio rozmiaru / przemalowywania innych stron karty.Szukałem więc sposobu, aby wyłączyć
WS_CLIPCHILDREN
początkowe malowanie, aby moja forma ładnie ładowała się pomalowana, lub lepiej, ale włączała ją tylko podczas zmiany rozmiaru mojej formy z wieloma komponentami.Sztuczka polega na tym, aby aplikacja zadzwoniła
CreateParams
w pożądanymWS_EX_COMPOSITED/WS_CLIPCHILDREN
stylu. Znalazłem tu hack ( https://web.archive.org/web/20161026205944/http://www.angryhacker.com/blog/archive/2010/07/21/how-to-get-rid-of- flicker-on-windows-forms-applications.aspx ) i działa świetnie. Dzięki AngryHacker!Umieszczam
TurnOnFormLevelDoubleBuffering()
wywołanie wResizeBegin
zdarzeniu formularza iTurnOffFormLevelDoubleBuffering()
wywołuję w formularzu zdarzenie ResizeEnd (lub po prostu zostawiam jeWS_CLIPCHILDREN
po początkowym poprawnym namalowaniu).źródło
Jeśli wykonujesz dowolne niestandardowe malowanie w kontrolce (np. Nadpisując OnPaint), możesz sam spróbować podwójnego buforowania.
I unieważnij swoją kontrolę za pomocą właściwości
NeedRepaint
W przeciwnym razie powyższa odpowiedź z SuspendLayout i ResumeLayout jest prawdopodobnie tym, czego potrzebujesz.
źródło
if (image != null) image.Dispose();
wcześniejimage = new Bitmap...
Wypróbuj metody BeginUpdate / EndUpdate LUB SuspendLayout / ResumeLayout. Zobacz następujące
Jak rozwiązać problemy z migotaniem zagnieżdżonych
formantów WinForm Migotanie podczas aktualizacji formantów w WinForms (np. DataGridView)
źródło
W głównym formularzu lub kontrolce użytkownika, w której znajduje się obraz tła, ustaw
BackgroundImageLayout
właściwość naCenter
lubStretch
. Zauważysz dużą różnicę podczas renderowania kontrolki użytkownika.źródło
Próbowałem dodać to jako komentarz, ale nie mam wystarczającej liczby punktów. To jedyna rzecz, która kiedykolwiek pomogła moim migotliwym problemom, dziękuję Hansowi za jego post. Dla każdego, kto używa konstruktora C ++, takiego jak ja, oto tłumaczenie
Dodaj deklarację CreateParams do głównego formularza aplikacji .h pliku np
i dodaj to do swojego pliku .cpp
źródło
Umieść kod poniżej w konstruktorze lub zdarzeniu OnLoad, a jeśli używasz jakiejś niestandardowej kontrolki użytkownika, która ma kontrolki podrzędne, musisz upewnić się, że te niestandardowe kontrolki są również podwójnie buforowane (nawet jeśli w dokumentacji MS mówią domyślnie jest ustawione na true).
Jeśli tworzysz niestandardową kontrolkę, możesz dodać tę flagę do swojego ctora:
Opcjonalnie możesz użyć tego kodu w swoim formularzu / kontrolce:
Iterujemy przez wszystkie kontrolki w formularzu / kontrolce i uzyskujemy dostęp do ich
DoubleBuffered
właściwości, a następnie zmieniamy ją na true, aby każda kontrolka w formularzu była podwójnie buforowana. Powodem, dla którego dokonujemy tutaj refleksji, jest to, że wyobraź sobie, że masz kontrolkę, która ma kontrolki podrzędne, które nie są dostępne, w ten sposób, nawet jeśli są to kontrolki prywatne, nadal zmienimy ich właściwość na true.Więcej informacji na temat techniki podwójnego buforowania można znaleźć tutaj .
Jest jeszcze jedna właściwość, którą zwykle nadpisuję, aby rozwiązać ten problem:
WS_EX_COMPOSITED
- Maluje wszystkie elementy potomne okna w kolejności malowania od dołu do góry przy użyciu podwójnego buforowania.Możesz znaleźć więcej takich flag stylów tutaj .
Mam nadzieję, że to pomoże!
źródło
Aby dodać do odpowiedzi udzielonej przez Hansa:
(Wersja TLDR: przezroczystość jest cięższa niż myślisz, wszędzie używaj tylko jednolitych kolorów)
Jeśli WS_EX_COMPOSITED, DoubleBuffered i WS_CLIPCHILDREN nie rozwiązały problemu z migotaniem (dla mnie WS_CLIPCHILDREN jeszcze gorzej), spróbuj tego: przejrzyj WSZYSTKIE kontrolki i cały kod i gdziekolwiek masz jakąkolwiek przezroczystość lub półprzezroczystość dla BackColor, ForeColor lub jakikolwiek inny kolor, po prostu go usuń, używaj tylko jednolitych kolorów. W większości przypadków, gdy uważasz, że po prostu muszą korzystać przejrzystości, nie. Zaprojektuj ponownie kod i kontrolki oraz użyj jednolitych kolorów. Miałem okropne, okropne migotanie, a program działał wolno. Po usunięciu przezroczystości znacznie przyspieszyło i nie ma migotania.
EDYCJA: Aby dodać więcej, właśnie odkryłem, że WS_EX_COMPOSITED nie musi obejmować całego okna, można go zastosować tylko do określonych kontrolek! Oszczędziło mi to wielu kłopotów. Po prostu ustaw niestandardową kontrolkę dziedziczoną z dowolnej kontrolki, której potrzebujesz, i wklej już opublikowane nadpisanie dla WS_EX_COMPOSITED. W ten sposób uzyskasz podwójny bufor niskiego poziomu tylko w tej kontrolce, unikając nieprzyjemnych efektów ubocznych w pozostałej części aplikacji!
źródło
Wiem, że to pytanie jest bardzo stare, ale chcę podzielić się z nim swoim doświadczeniem.
Miałem sporo problemów z
Tabcontrol
migotaniem w formularzu z nadpisaniemOnPaint
i / lubOnPaintBackGround
w Windows 8 używając .NET 4.0.Jedyną myślą, która pracowała była NIE UŻYWAĆ ten
Graphics.DrawImage
sposób wOnPaint
zadajnikami, innymi słowy, kiedy losowanie przeprowadzono bezpośrednio do grafiki pod warunkiem przezPaintEventArgs
nawet malowanie wszystkich prostokąta migotanie zniknął. Ale jeśli wywołaszDrawImage
metodę, nawet rysując obciętą bitmapę (utworzoną do podwójnego buforowania), pojawi się migotanie.Mam nadzieję, że to pomoże!
źródło
Połączyłem tę poprawkę migotania i tę poprawkę czcionki , a następnie musiałem dodać trochę własnego kodu, aby uruchomić licznik czasu podczas malowania, aby unieważnić TabControl, gdy znika z ekranu iz powrotem itp.
Wszystkie trzy sprawiają, że:
Nie jestem twórcą, ale z tego, co rozumiem, mapa bitowa omija wszystkie błędy.
To była jedyna rzecz, która ostatecznie rozwiązała dla mnie migotanie TabControl (z ikonami).
film z wynikami różnic: vanilla tabcontrol vs tabcontrolex
http://gfycat.com/FineGlitteringDeermouse
ps. będziesz musiał ustawić HotTrack = true, ponieważ to również naprawia ten błąd
źródło
Czy wypróbowałeś
Control.DoubleBuffered
Property?Również to i to może pomóc.
źródło
Nie ma potrzeby podwójnego buforowania i tych wszystkich rzeczy ...
Proste rozwiązanie ...
Jeśli używasz interfejsu MDI, po prostu wklej poniższy kod w formularzu głównym. To usunie wszelkie migotanie ze stron. Jednak niektóre strony, które wymagają więcej czasu na załadowanie, pojawią się w ciągu 1 lub 2 sekund. Jest to jednak lepsze niż wyświetlanie migoczącej strony, na której każdy element pojawia się jeden po drugim.
To jedyne najlepsze rozwiązanie dla całej aplikacji. Zobacz kod do umieszczenia w głównym formularzu:
źródło