In meiner Anwendung wechsle ich ständig von einem Steuerelement zum anderen. Ich habe nein geschaffen. von Benutzersteuerelementen, aber während der Navigation flackern meine Steuerelemente. Die Aktualisierung dauert 1 oder 2 Sekunden. Ich habe versucht, dies einzustellen
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
aber es hat nicht geholfen ... Jedes Steuerelement hat das gleiche Hintergrundbild mit unterschiedlichen Steuerelementen. Also, was ist die Lösung dafür.
Danke.
c#
winforms
user-controls
flicker
Royson
quelle
quelle
UpdateStyles
nach dem Einstellen angerufen ? Es ist schlecht dokumentiert, kann aber manchmal notwendig sein.Antworten:
Es ist nicht die Art von Flimmern, die durch Doppelpufferung gelöst werden kann. Weder BeginUpdate noch SuspendLayout. Sie haben zu viele Steuerelemente, das BackgroundImage kann es noch viel schlimmer machen.
Es beginnt, wenn sich das UserControl selbst malt. Es zeichnet das BackgroundImage und hinterlässt Löcher in den Fenstern der untergeordneten Steuerung. Jedes untergeordnete Steuerelement erhält dann eine Nachricht, um sich selbst zu malen. Sie füllen das Loch mit ihrem Fensterinhalt aus. Wenn Sie viele Steuerelemente haben, sind diese Löcher für den Benutzer für eine Weile sichtbar. Sie sind normalerweise weiß und bilden einen schlechten Kontrast zum BackgroundImage, wenn es dunkel ist. Oder sie können schwarz sein, wenn für das Formular die Eigenschaft Deckkraft oder Transparenzschlüssel festgelegt ist, die sich stark von fast allem abhebt.
Dies ist eine ziemlich grundlegende Einschränkung von Windows Forms. Sie hängt von der Art und Weise ab, wie Windows Windows rendert. Übrigens von WPF behoben, verwendet es keine Fenster für untergeordnete Steuerelemente. Sie möchten das gesamte Formular einschließlich der untergeordneten Steuerelemente doppelt puffern. Das ist möglich, überprüfen Sie meinen Code in diesem Thread für die Lösung. Es hat jedoch Nebenwirkungen und erhöht die Malgeschwindigkeit nicht wirklich. Der Code ist einfach. Fügen Sie ihn in Ihr Formular ein (nicht in das Benutzersteuerelement):
Es gibt viele Dinge, die Sie tun können, um die Malgeschwindigkeit zu verbessern, bis das Flimmern nicht mehr wahrnehmbar ist. Beginnen Sie mit dem BackgroundImage. Sie können sehr teuer sein, wenn das Quellbild groß ist und verkleinert werden muss, um in das Steuerelement zu passen. Ändern Sie die BackgroundImageLayout-Eigenschaft in "Tile". Wenn dies zu einer spürbaren Beschleunigung führt, kehren Sie zu Ihrem Malprogramm zurück und ändern Sie die Bildgröße, um eine bessere Übereinstimmung mit der typischen Steuerelementgröße zu erzielen. Oder schreiben Sie Code in die OnResize () -Methode des UC, um eine Kopie des Bildes mit der richtigen Größe zu erstellen, damit die Größe nicht jedes Mal geändert werden muss, wenn das Steuerelement neu gezeichnet wird. Verwenden Sie für diese Kopie das Pixelformat Format32bppPArgb. Es wird etwa zehnmal schneller gerendert als jedes andere Pixelformat.
Als nächstes können Sie verhindern, dass die Löcher so auffällig sind und einen schlechten Kontrast zum Bild bilden. Sie können das WS_CLIPCHILDREN-Stilflag für die UC deaktivieren. Dieses Flag verhindert, dass die UC in dem Bereich malt, in dem sich die untergeordneten Steuerelemente befinden. Fügen Sie diesen Code in den Code von UserControl ein:
Die untergeordneten Steuerelemente malen sich jetzt über das Hintergrundbild. Sie können immer noch sehen, wie sie sich einzeln malen, aber das hässliche weiße oder schwarze Zwischenloch ist nicht sichtbar.
Last but not least ist die Reduzierung der Anzahl der untergeordneten Steuerelemente immer ein guter Ansatz, um Probleme beim langsamen Malen zu lösen. Überschreiben Sie das OnPaint () - Ereignis der UC und zeichnen Sie, was jetzt in einem untergeordneten Element angezeigt wird. Bestimmte Beschriftungen und PictureBox sind sehr verschwenderisch. Praktisch für Zeigen und Klicken, aber ihre leichte Alternative (Zeichnen einer Zeichenfolge oder eines Bildes) benötigt in Ihrer OnPaint () -Methode nur eine einzige Codezeile.
quelle
Dies ist ein echtes Problem, und die Antwort, die Hans Passant gab, ist großartig, um das Flimmern zu retten. Es gibt jedoch Nebenwirkungen, wie er erwähnte, und sie können hässlich sein (UI hässlich). Wie bereits erwähnt, "Sie können das
WS_CLIPCHILDREN
Stilflag für die UC deaktivieren", aber das deaktiviert es nur für eine UC. Die Komponenten im Hauptformular weisen weiterhin Probleme auf.Beispiel: Eine Bildlaufleiste wird nicht gemalt, da sie sich technisch im untergeordneten Bereich befindet. Die untergeordnete Komponente zeichnet die Bildlaufleiste jedoch nicht, sodass sie erst mit der Maus gezeichnet wird (oder ein anderes Ereignis sie auslöst).
Außerdem funktionieren animierte Symbole (Ändern von Symbolen in einer Warteschleife) nicht. Durch das Entfernen von
tabPage.ImageKey
Symbolen auf einem wird die Größe der anderen Registerkarten nicht entsprechend geändert / neu gezeichnet.Daher suchte ich nach einer Möglichkeit, das
WS_CLIPCHILDREN
erste Mal zu deaktivieren, damit mein Formular gut gemalt geladen wird, oder besser, es nur einzuschalten, während ich die Größe meines Formulars mit vielen Komponenten verändere.Der Trick besteht darin, die Anwendung dazu zu bringen,
CreateParams
mit dem gewünschtenWS_EX_COMPOSITED/WS_CLIPCHILDREN
Stil aufzurufen . Ich habe hier einen Hack gefunden ( 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 ) und es funktioniert großartig. Danke AngryHacker!Ich setze den
TurnOnFormLevelDoubleBuffering()
Aufruf in das FormularereignisResizeBegin
undTurnOffFormLevelDoubleBuffering()
rufe das Formular ResizeEnd-Ereignis auf (oder lasse es einfach,WS_CLIPCHILDREN
nachdem es anfänglich richtig gezeichnet wurde .)quelle
Wenn Sie ein benutzerdefiniertes Bild im Steuerelement erstellen (dh OnPaint überschreiben), können Sie die doppelte Pufferung selbst ausprobieren.
Und machen Sie Ihre Kontrolle mit einer Eigenschaft ungültig
NeedRepaint
Andernfalls ist die obige Antwort mit SuspendLayout und ResumeLayout wahrscheinlich genau das, was Sie wollen.
quelle
if (image != null) image.Dispose();
vorimage = new Bitmap...
Versuchen Sie es mit den Methoden BeginUpdate / EndUpdate ODER SuspendLayout / ResumeLayout. Weitere
Informationen finden Sie im Folgenden. So beheben Sie Probleme mit dem Flimmern verschachtelter Winform-Steuerelemente
Flackern bei Aktualisierungen von Steuerelementen in WinForms (z. B. DataGridView)
quelle
Setzen Sie im Hauptformular oder Benutzersteuerelement, in dem sich das Hintergrundbild befindet, die
BackgroundImageLayout
Eigenschaft aufCenter
oderStretch
. Sie werden einen großen Unterschied feststellen, wenn das Benutzersteuerelement gerendert wird.quelle
Ich habe versucht, dies als Kommentar hinzuzufügen, aber ich habe nicht genug Punkte. Dies ist das einzige, was meinen flackernden Problemen jemals geholfen hat. Vielen Dank an Hans für seinen Beitrag. Für alle, die C ++ Builder wie mich verwenden, ist hier die Übersetzung
Fügen Sie die CreateParams-Deklaration zur .h-Datei des Hauptformulars Ihrer Anwendung hinzu, z
und fügen Sie dies Ihrer CPP-Datei hinzu
quelle
Fügen Sie den folgenden Code in Ihren Konstruktor oder Ihr OnLoad-Ereignis ein. Wenn Sie ein benutzerdefiniertes Benutzersteuerelement mit Untersteuerelementen verwenden, müssen Sie sicherstellen, dass diese benutzerdefinierten Steuerelemente auch doppelt gepuffert sind (auch wenn dies in der MS-Dokumentation angegeben ist) es ist standardmäßig auf true gesetzt).
Wenn Sie ein benutzerdefiniertes Steuerelement erstellen, möchten Sie möglicherweise dieses Flag zu Ihrem ctor hinzufügen:
Optional können Sie diesen Code in Ihrem Formular / Steuerelement verwenden:
Wir durchlaufen alle Steuerelemente im Formular / Steuerelement und greifen auf deren
DoubleBuffered
Eigenschaften zu. Anschließend ändern wir sie in true, um jedes Steuerelement im Formular doppelt zu puffern. Der Grund, warum wir hier nachdenken, ist, dass Sie sich vorstellen, dass Sie ein Steuerelement haben, dessen untergeordnete Steuerelemente nicht zugänglich sind. Selbst wenn es sich um private Steuerelemente handelt, ändern wir ihre Eigenschaft dennoch in true.Weitere Informationen zur Doppelpuffertechnik finden Sie hier .
Es gibt eine andere Eigenschaft, die ich normalerweise überschreibe, um dieses Problem zu lösen:
WS_EX_COMPOSITED
- Malt alle Nachkommen eines Fensters in der Reihenfolge von unten nach oben mit doppelter Pufferung.Weitere dieser Stilflaggen finden Sie hier .
Hoffentlich hilft das!
quelle
Nur um die Antwort zu ergänzen, die Hans gab:
(TLDR-Version: Transparenz ist schwerer als Sie denken, verwenden Sie überall nur Volltonfarben)
Wenn WS_EX_COMPOSITED, DoubleBuffered und WS_CLIPCHILDREN Ihr Flimmern nicht gelöst haben (für mich hat WS_CLIPCHILDREN es noch schlimmer gemacht), versuchen Sie Folgendes: Gehen Sie ALLE Ihre Steuerelemente und Ihren gesamten Code durch und überall dort, wo Sie Transparenz oder Halbtransparenz für BackColor, ForeColor oder haben Jede andere Farbe, entfernen Sie sie einfach und verwenden Sie nur Volltonfarben. In den meisten Fällen , in denen Sie denken , dass Sie gerade haben Transparenz zu verwenden, tun Sie nicht. Gestalten Sie Ihren Code und Ihre Steuerelemente neu und verwenden Sie Volltonfarben. Ich hatte schreckliches, schreckliches Flackern und das Programm lief träge. Sobald ich die Transparenz entfernt habe, hat sie sich erheblich beschleunigt und es gibt kein Flimmern.
BEARBEITEN: Um weiter hinzuzufügen, habe ich gerade festgestellt, dass WS_EX_COMPOSITED nicht fensterweit sein muss, sondern nur auf bestimmte Steuerelemente angewendet werden kann! Das hat mir viel Ärger erspart. Erstellen Sie einfach ein benutzerdefiniertes Steuerelement, das von dem gewünschten Steuerelement geerbt wurde, und fügen Sie die bereits veröffentlichte Überschreibung für WS_EX_COMPOSITED ein. Auf diese Weise erhalten Sie nur auf diesem Steuerelement einen Doppelpuffer auf niedriger Ebene, wodurch die unangenehmen Nebenwirkungen im Rest der Anwendung vermieden werden!
quelle
Ich weiß, dass diese Frage sehr alt ist, möchte aber meine Erfahrungen dazu geben.
Ich hatte viele Probleme mit dem
Tabcontrol
Flackern in einem Formular mit überschriebenemOnPaint
und / oderOnPaintBackGround
in Windows 8 unter Verwendung von .NET 4.0.Der einzige Gedanke, der funktioniert hat, war, die Methode NICHT
Graphics.DrawImage
beimOnPaint
Überschreiben zu verwenden, mit anderen Worten, wenn das Zeichnen direkt auf die Grafiken erfolgte, die durch dasPaintEventArgs
sogar das Malen des gesamten Rechtecks bereitgestellt wurden , verschwand das Flackern. Wenn Sie dieDrawImage
Methode aufrufen und sogar eine abgeschnittene Bitmap zeichnen (erstellt für doppelte Pufferung), wird das Flimmern angezeigt.Ich hoffe es hilft!
quelle
Ich habe diesen Flimmer-Fix und diesen Font-Fix kombiniert , dann musste ich ein bisschen meinen eigenen Code hinzufügen, um einen Timer für das Malen zu starten, um das TabControl ungültig zu machen, wenn es außerhalb des Bildschirms und zurück geht usw.
Alle drei machen das:
Ich bin nicht der Schöpfer, aber soweit ich weiß, umgeht die Bitmap den ganzen Fehler.
Dies war das einzige, was TabControl (mit Symbolen) für mich endgültig gelöst hat.
Unterschied Ergebnis Video: Vanille Tabcontrol vs Tabcontrolex
http://gfycat.com/FineGlitteringDeermouse
ps. Sie müssen HotTrack = true setzen, da dies auch diesen Fehler behebt
quelle
Haben Sie
Control.DoubleBuffered
Property ausprobiert ?Auch dies und das könnte helfen.
quelle
Es ist keine doppelte Pufferung und all das Zeug nötig ...
Eine einfache Lösung ...
Wenn Sie die MDI-Schnittstelle verwenden, fügen Sie einfach den folgenden Code in das Hauptformular ein. Dadurch wird jegliches Flackern von den Seiten entfernt. Einige Seiten, die mehr Zeit zum Laden benötigen, werden jedoch in 1 oder 2 Sekunden angezeigt. Dies ist jedoch besser, als eine flackernde Seite anzuzeigen, auf der jedes Element einzeln angezeigt wird.
Dies ist die einzig beste Lösung für die gesamte Anwendung. Siehe den Code, der in das Hauptformular eingefügt werden soll:
quelle