Tengo un control al que tengo que hacer grandes modificaciones. Me gustaría evitar que se vuelva a dibujar por completo mientras hago eso: SuspendLayout y ResumeLayout no son suficientes. ¿Cómo suspendo la pintura para un control y sus hijos?
184
Respuestas:
En mi trabajo anterior, tuvimos problemas para lograr que nuestra rica aplicación de interfaz de usuario pintara al instante y sin problemas. Estábamos usando controles estándar .Net, controles personalizados y controles devexpress.
Después de mucho googlear y usar el reflector, me encontré con el mensaje WM_SETREDRAW win32. Esto realmente detiene el dibujo de controles mientras los actualiza y se puede aplicar, IIRC al panel principal / que contiene.
Esta es una clase muy muy simple que demuestra cómo usar este mensaje:
Hay discusiones más completas sobre esto: google para C # y WM_SETREDRAW, por ejemplo
C # Jitter
Suspender diseños
Y a quien corresponda, este es un ejemplo similar en VB:
fuente
Control
clase base para todos los controles WinForms ya hace para los métodosBeginUpdate
yEndUpdate
. Enviar el mensaje usted mismo no es mejor que usar esos métodos para hacer el trabajo pesado por usted, y ciertamente no puede producir resultados diferentes.Control.Handle
forzará la creación del identificador de ventana y podría afectar el rendimiento. Por ejemplo, si movía un control en un formulario antes de que se mostrara, si llama a esto deSuspendDrawing
antemano, su movimiento será más lento. Probablemente debería tenerif (!parent.IsHandleCreated) return
controles en ambos métodos.La siguiente es la misma solución de ng5000 pero no usa P / Invoke.
fuente
Message
y dóndeNativeWindow
están; buscar documentación para una clase llamadaMessage
no es realmente tan entretenido.Invalidate()
no funciona tan bien como aRefresh()
menos que siga uno de todos modos.Usualmente uso una pequeña versión modificada de la respuesta de ngLink .
Esto permite que las llamadas de suspensión / reanudación se aniden. Debes asegurarte de hacer coincidir cada uno
SuspendDrawing
con unResumeDrawing
. Por lo tanto, probablemente no sería una buena idea hacerlos públicos.fuente
SuspendDrawing(); try { DrawSomething(); } finally { ResumeDrawing(); }
. Otra opción es implementar esto en unaIDisposable
clase y encerrar la parte del dibujo en unausing
declaración. El identificador se pasaría al constructor, que suspendería el dibujo.DllImport
declaraswParam
comobool
?Para ayudar a no olvidar volver a habilitar el dibujo:
uso:
fuente
action()
lanza una excepción? (Use un intento / finalmente)Una buena solución sin usar interoperabilidad:
Como siempre, simplemente habilite DoubleBuffered = true en su CustomControl. Luego, si tiene contenedores como FlowLayoutPanel o TableLayoutPanel, obtenga una clase de cada uno de estos tipos y, en los constructores, habilite el almacenamiento en búfer doble. Ahora, simplemente use sus contenedores derivados en lugar de los contenedores Windows.Forms.
fuente
Basado en la respuesta de ng5000, me gusta usar esta extensión:
Utilizar:
fuente
Aquí hay una combinación de ceztko y ng5000 para traer una versión de extensiones VB que no usa pinvoke
fuente
Sé que esta es una vieja pregunta, ya respondida, pero aquí está mi opinión sobre esto; Refactoré la suspensión de actualizaciones en un ID desechable, de esa manera puedo adjuntar las declaraciones que quiero ejecutar en una
using
declaración.fuente
Esto es aún más simple y quizás hacky, ya que puedo ver una gran cantidad de músculo GDI en este hilo , y obviamente solo es una buena opción para ciertos escenarios. YMMV
En mi caso, utilizo lo que denominaré
Load
Control de usuario "principal", y durante el evento, simplemente elimino el control para ser manipulado de la.Controls
colección principal y el elemento principalOnPaint
se encargan de pintar completamente al niño control de cualquier manera especial ... desconectando por completo las capacidades de pintura del niño.Ahora, paso la rutina de pintura de mi hijo a un método de extensión basado en este concepto de Mike Gold para imprimir formularios de Windows .
Aquí necesito un subconjunto de etiquetas para representar perpendicular al diseño:
Luego, eximo el control infantil de ser pintado, con este código en el
ParentUserControl.Load
controlador de eventos:Luego, en el mismo ParentUserControl, pintamos el control para ser manipulado desde cero:
Una vez que aloje ParentUserControl en algún lugar, por ejemplo, un formulario de Windows, descubro que mi Visual Studio 2015 representa el formulario correctamente en tiempo de diseño y en tiempo de ejecución:
Ahora, dado que mi manipulación particular gira el control infantil 90 grados, estoy seguro de que todos los puntos calientes y la interactividad se han destruido en esa región, pero el problema que estaba resolviendo era todo por una etiqueta de paquete que necesitaba previsualizar e imprimir, que funcionó bien para mí
Si hay formas de reintroducir los puntos calientes y el control de mi control huérfano a propósito, me encantaría aprender sobre eso algún día (no para este escenario, por supuesto, pero ... solo para aprender). Por supuesto, WPF admite esa locura OOTB ... pero ... oye ... WinForms es muy divertido, ¿verdad?
fuente
O simplemente use
Control.SuspendLayout()
yControl.ResumeLayout()
.fuente