J'ai un contrôle auquel je dois apporter de grandes modifications. Je voudrais l'empêcher complètement de se redessiner pendant que je fais cela - SuspendLayout et ResumeLayout ne suffisent pas. Comment suspendre la peinture pour un contrôle et ses enfants?
184
Réponses:
Lors de mon travail précédent, nous avons eu du mal à faire en sorte que notre riche application d'interface utilisateur peigne instantanément et en douceur. Nous utilisions des contrôles .Net standard, des contrôles personnalisés et des contrôles devexpress.
Après beaucoup d'utilisation de Google et de réflecteur, je suis tombé sur le message WM_SETREDRAW win32. Cela arrête vraiment le dessin des contrôles pendant que vous les mettez à jour et peut être appliqué, IIRC au panneau parent / contenant.
Il s'agit d'une classe très très simple montrant comment utiliser ce message:
Il y a des discussions plus complètes à ce sujet - google pour C # et WM_SETREDRAW, par exemple
C # Jitter
Suspendre des mises en page
Et à qui cela peut concerner, voici un exemple similaire en VB:
la source
Control
classe de base pour tous les contrôles WinForms fait déjà pour laBeginUpdate
etEndUpdate
méthodes. Envoyer le message vous-même n'est pas mieux que d'utiliser ces méthodes pour faire le gros du travail à votre place, et ne peut certainement pas produire des résultats différents.Control.Handle
forcera la création du handle de fenêtre et pourrait affecter les performances. Par exemple, si vous déplaciez un contrôle sur un formulaire avant qu'il ne soit affiché, si vous appelez celaSuspendDrawing
au préalable, votre déplacement sera plus lent. Devrait probablement avoir desif (!parent.IsHandleCreated) return
contrôles dans les deux méthodes.Ce qui suit est la même solution que ng5000 mais n'utilise pas P / Invoke.
la source
Message
et oùNativeWindow
sont; rechercher de la documentation pour une classe nomméeMessage
n'est pas vraiment divertissant.Invalidate()
ne fonctionne pas aussi bien qu'àRefresh()
moins d' être suivi par un de toute façon.J'utilise généralement une version légèrement modifiée de la réponse de ngLink .
Cela permet d'imbriquer les appels de suspension / reprise. Vous devez vous assurer de faire correspondre chacun
SuspendDrawing
avec unResumeDrawing
. Par conséquent, ce ne serait probablement pas une bonne idée de les rendre publics.la source
SuspendDrawing(); try { DrawSomething(); } finally { ResumeDrawing(); }
. Une autre option consiste à implémenter ceci dans uneIDisposable
classe et à entourer la partie du dessin dans uneusing
déclaration. Le handle serait passé au constructeur, ce qui suspendrait le dessin.DllImport
déclarezwParam
commebool
?Pour vous aider à ne pas oublier de réactiver le dessin:
usage:
la source
action()
lance une exception? (Utilisez un essai / enfin)Une belle solution sans utiliser l'interopérabilité:
Comme toujours, activez simplement DoubleBuffered = true sur votre CustomControl. Ensuite, si vous avez des conteneurs tels que FlowLayoutPanel ou TableLayoutPanel, dérivez une classe de chacun de ces types et dans les constructeurs, activez la double mise en mémoire tampon. Maintenant, utilisez simplement vos conteneurs dérivés au lieu des conteneurs Windows.Forms.
la source
Sur la base de la réponse de ng5000, j'aime utiliser cette extension:
Utilisation:
la source
Voici une combinaison de ceztko et de ng5000 pour apporter une version d'extensions VB qui n'utilise pas pinvoke
la source
Je sais que c'est une vieille question à laquelle on a déjà répondu, mais voici mon point de vue à ce sujet; J'ai refactorisé la suspension des mises à jour dans un IDisposable - de cette façon, je peux inclure les déclarations que je veux exécuter dans une
using
déclaration.la source
C'est encore plus simple, et peut-être hacky - car je peux voir beaucoup de muscle GDI sur ce fil , et ce n'est évidemment qu'un bon choix pour certains scénarios.YMMV
Dans mon scénario, j'utilise ce que j'appellerai un UserControl "Parent" - et pendant l'
Load
événement, je supprime simplement le contrôle à manipuler de la.Controls
collection Parent et le Parent'sOnPaint
s'occupe de peindre complètement l'enfant contrôler de quelque manière que ce soit ... en mettant pleinement hors ligne les capacités de peinture de l'enfant.Maintenant, je confie la routine de peinture de mon enfant à une méthode d'extension basée sur ce concept de Mike Gold pour l'impression de formulaires Windows .
Ici, j'ai besoin d'un sous-ensemble d'étiquettes pour rendre perpendiculaire à la mise en page:
Ensuite, j'exempte le contrôle enfant d'être peint, avec ce code dans le
ParentUserControl.Load
gestionnaire d'événements:Ensuite, dans le même ParentUserControl, nous peignons le contrôle à manipuler à partir de zéro:
Une fois que vous hébergez le ParentUserControl quelque part, par exemple un formulaire Windows - je constate que mon Visual Studio 2015 rend le formulaire correctement au moment du design ainsi qu'au moment de l'exécution:
Maintenant, comme ma manipulation particulière fait pivoter le contrôle enfant de 90 degrés, je suis sûr que tous les points chauds et l'interactivité ont été détruits dans cette région - mais le problème que je résolvais concernait uniquement une étiquette d'emballage qui devait être prévisualisée et imprimée, qui a bien fonctionné pour moi.
S'il y a des moyens de réintroduire les points chauds et le contrôle dans mon contrôle volontairement orphelin - j'aimerais en savoir plus un jour (pas pour ce scénario, bien sûr, mais ... juste pour apprendre). Bien sûr, WPF prend en charge une telle folie OOTB .. mais .. hé .. WinForms est encore tellement amusant, non?
la source
Ou utilisez simplement
Control.SuspendLayout()
etControl.ResumeLayout()
.la source