Ich habe ein Steuerelement, an dem ich große Änderungen vornehmen muss. Ich möchte dabei vollständig verhindern, dass es neu gezeichnet wird - SuspendLayout und ResumeLayout reichen nicht aus. Wie setze ich das Malen für ein Steuerelement und seine Kinder aus?
184
Antworten:
Bei meinem vorherigen Job hatten wir Probleme damit, dass unsere umfangreiche UI-App sofort und reibungslos malt. Wir verwendeten Standard-.NET-Steuerelemente, benutzerdefinierte Steuerelemente und Devexpress-Steuerelemente.
Nach vielem googeln und Reflektornutzung stieß ich auf die Win32-Nachricht WM_SETREDRAW. Dadurch wird das Zeichnen von Steuerelementen wirklich gestoppt, während Sie sie aktualisieren, und es kann IIRC auf das übergeordnete / enthaltende Bedienfeld angewendet werden.
Dies ist eine sehr sehr einfache Klasse, die zeigt, wie diese Nachricht verwendet wird:
Es gibt ausführlichere Diskussionen dazu - Google für C # und WM_SETREDRAW, z
C # Jitter
Layouts anhalten
Und wen es betrifft, ist dies ein ähnliches Beispiel in VB:
quelle
Control
Basisklasse für alle WinForms-Steuerelemente bereits für die MethodenBeginUpdate
undEndUpdate
. Das Senden der Nachricht selbst ist nicht besser als das Verwenden dieser Methoden, um das schwere Heben für Sie zu erledigen, und kann mit Sicherheit keine unterschiedlichen Ergebnisse erzielen.Control.Handle
erzwingt das Erstellen des Fensterhandles und kann die Leistung beeinträchtigen. Wenn Sie beispielsweise ein Steuerelement in einem FormularSuspendDrawing
verschoben haben, bevor es angezeigt wurde , ist Ihre Verschiebung langsamer , wenn Sie dies zuvor aufrufen . Wahrscheinlich solltenif (!parent.IsHandleCreated) return
beide Methoden überprüft werden.Das Folgende ist die gleiche Lösung von ng5000, verwendet jedoch nicht P / Invoke.
quelle
Message
und woNativeWindow
; Das Durchsuchen der Dokumentation nach einer Klasse namensMessage
ist nicht wirklich unterhaltsam.Invalidate()
funktioniert nicht so gut wieRefresh()
wenn nicht einer folgt.Normalerweise verwende ich eine etwas modifizierte Version von ngLinks Antwort .
Dadurch können Anrufe unterbrochen / fortgesetzt werden. Sie müssen sicherstellen, dass jedes
SuspendDrawing
mit einem übereinstimmtResumeDrawing
. Daher wäre es wahrscheinlich keine gute Idee, sie öffentlich zu machen.quelle
SuspendDrawing(); try { DrawSomething(); } finally { ResumeDrawing(); }
. Eine andere Möglichkeit besteht darin, dies in einerIDisposable
Klasse zu implementieren und den Zeichnungsteil in eineusing
Anweisung einzuschließen. Das Handle würde an den Konstruktor übergeben, der das Zeichnen aussetzen würde.DllImport
deklariert IhrwParam
alsbool
?Um nicht zu vergessen, dass das Zeichnen wieder aktiviert werden kann:
Verwendung:
quelle
action()
eine Ausnahme ausgelöst wird? (Verwenden Sie einen Versuch / endlich)Eine schöne Lösung ohne Interop:
Aktivieren Sie wie immer einfach DoubleBuffered = true auf Ihrem CustomControl. Wenn Sie dann Container wie FlowLayoutPanel oder TableLayoutPanel haben, leiten Sie eine Klasse von jedem dieser Typen ab und aktivieren Sie in den Konstruktoren die doppelte Pufferung. Verwenden Sie jetzt einfach Ihre abgeleiteten Container anstelle der Windows.Forms-Container.
quelle
Basierend auf der Antwort von ng5000 verwende ich gerne diese Erweiterung:
Verwenden:
quelle
Hier ist eine Kombination aus ceztko und ng5000, um eine VB-Erweiterungsversion zu bringen, die kein Pinvoke verwendet
quelle
Ich weiß, dass dies eine alte Frage ist, die bereits beantwortet wurde, aber hier ist meine Meinung dazu. Ich habe die Aussetzung von Updates in ein IDisposable umgestaltet. Auf diese Weise kann ich die Anweisungen, die ich ausführen möchte, in eine
using
Anweisung einschließen .quelle
Dies ist noch einfacher und vielleicht hacky - da ich in diesem Thread viel GDI-Muskel sehen kann und offensichtlich nur für bestimmte Szenarien gut geeignet ist. YMMV
In meinem Szenario verwende ich das, was ich als "Eltern" -Benutzersteuerung bezeichne - und während des
Load
Ereignisses entferne ich einfach das zu manipulierende Steuerelement aus der.Controls
Sammlung der Eltern, und die ElternOnPaint
kümmern sich darum, das Kind vollständig zu malen Kontrolle auf welche Art und Weise auch immer. Die Malfähigkeiten des Kindes werden vollständig offline geschaltet.Jetzt übergebe ich meine Kindermalroutine an eine Erweiterungsmethode, die auf diesem Konzept von Mike Gold zum Drucken von Windows-Formularen basiert .
Hier benötige ich eine Untergruppe von Beschriftungen, um senkrecht zum Layout zu rendern :
Dann befreie ich das untergeordnete Steuerelement mit diesem Code im
ParentUserControl.Load
Ereignishandler vom Zeichnen:Dann malen wir in demselben ParentUserControl das zu manipulierende Steuerelement von Grund auf neu:
Sobald Sie das ParentUserControl irgendwo gehostet haben, z. B. in einem Windows-Formular, stelle ich fest, dass mein Visual Studio 2015 das Formular sowohl zur Entwurfszeit als auch zur Laufzeit korrekt wiedergibt :
Jetzt, da meine spezielle Manipulation die Kindersteuerung um 90 Grad dreht, bin ich sicher, dass alle Hotspots und Interaktivität in dieser Region zerstört wurden - aber das Problem, das ich gelöst habe, war alles für ein Paketetikett, das in der Vorschau angezeigt und gedruckt werden musste. was für mich gut geklappt hat.
Wenn es Möglichkeiten gibt, die Hot Spots und die Kontrolle wieder in meine absichtlich verwaiste Kontrolle einzuführen, würde ich gerne eines Tages davon erfahren (natürlich nicht für dieses Szenario, aber ... nur um zu lernen). Natürlich unterstützt WPF solche Verrücktheit OOTB .. aber .. hey .. WinForms macht immer noch so viel Spaß, oder?
quelle
Oder verwenden Sie einfach
Control.SuspendLayout()
undControl.ResumeLayout()
.quelle