Tengo una biblioteca de unos «controles personalizados». Esencialmente tenemos nuestros propios botones, más redondo paneles de esquina, y un par de groupboxes con algunos de encargo de la pintura. A pesar de las «matemáticas» en la OnPaint métodos, los controles son bastante estándar. La mayoría de las veces, todo lo que hacemos es dibujar las esquinas redondeadas y agregar gradiente para el fondo. Hacemos uso de GDI+ para todos los que.

Estos controles están bien (y muy bonito de acuerdo a nuestros clientes), sin embargo y a pesar de la DoubleBuffer, usted puede ver algunas de volver a dibujar, sobre todo cuando hay 20++ botones (por ejemplo) en el mismo formulario. En el formulario de carga se ven los botones de dibujo… lo cual es molesto.

Estoy bastante seguro de que nuestros botones no son los más rápidos cosa en la tierra, pero mi pregunta es: si el doble búfer está en «on», no todos los que redibujar suceder en el fondo y el subsistema de Windows debe mostrar los resultados «al instante» ?

Por otro lado, si hay un «complejo» bucle foreach que va a crear etiquetas, añadir a un panel (de doble buffer) y cambiar sus propiedades, si nos suspendlayout del panel antes de que el bucle y reanudar el diseño del panel cuando el lazo es más, no todos estos controles (botones y etiquetas) aparecen «casi al instante»? Esto no sucede así, se puede ver el panel de ser llenados.

Alguna idea de por qué esto no está sucediendo? Sé que es difícil de evaluar sin código de ejemplo, pero que es difícil de replicar demasiado. Yo podría hacer un video con una cámara, pero confía en mí en esto, no es rápido 🙂

  • Usted también debe tratar de suspender/reanudar redibujar las operaciones de…ver mi respuesta actualizada.
  • Definitivamente tienes un problema de rendimiento. No creo que el dibujo de los gradientes y los cuartos de círculo debe ser lenta.
  • Bueno, como ya he dicho, la biblioteca de interfaz de usuario no es el más rápido, pero también tenemos un montón de GDI+ código de dibujo para hacer que el botón buscar como queremos que se vea. No es sólo un empate.arco x 4 y pintar la superficie con un Degradado. Creo que vamos a tener que trabajar en eso también… pero me preguntaba si había una manera de acelerar. Si el doble de búferes, debe mostrar de manera rápida cuando se «voltea», ¿no?
  • Todavía estoy investigando el tema, informará en breve. Gracias por las ideas tan lejos.

10 Comentarios

  1. 12

    Hemos visto también este problema.

    Forma en que he visto a «fix» para suspender completamente el dibujo de el control hasta que estamos listos para ir. Para lograr esto, se envía el mensaje WM_SETREDRAW para el control de:

    //Note that WM_SetRedraw = 0XB
    
    //Suspend drawing.
    UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
    
    ...
    
    //Resume drawing.
    UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
    • Ya he publicado este…
    • Es que C++? No tengo UsafeSharedNativeMethods… que me estoy perdiendo una referencia? (jejeje me suena como vcs compilador) 😉
    • Puede ser C++, pero es el mismo concepto que he incluido en el enlace en mi respuesta.
    • No es C++, es una manera estándar de nomenclatura de su PInvoke clase. Se supone que para crear su propia clase estática y agregar un PInvoke método llamado SendMessage. WindowMessages es también, obviamente, un usuario definido por el enum con los valores especificados correctamente a partir de la API de Win32. Finalmente, Adam, no publicar esto ya, que acaba de publicar un enlace, y su actitud es bastante molesto.
  2. 11

    Una de las cosas que usted debe mirar es si ha establecido BackColor=Transparente en cualquiera de los controles de los paneles. El BackColor=Transparente degradar significativamente el rendimiento de la representación, especialmente si los padres de los paneles son el uso de degradados.

    De Formularios Windows forms no uso real de la transparencia, sino que se utiliza «falso» uno. Cada niño de control de la pintura llamada genera pintura llamada de los padres para los padres puede pintar a su fondo sobre los cuales el niño pinta de control de su contenido, por lo que aparece transparente.

    Así que si usted tiene 50 controles de niño que va a generar más de 50 pintura llamadas en el control de los padres para el fondo de la pintura. Y ya que los gradientes son generalmente más lento que va a ver una degradación del rendimiento.

    Espero que esto ayude.

  3. 9

    Voy a abordar su problema de un rendimiento de ángulo.

    bucle foreach que va a crear etiquetas,
    agregar a un panel (de doble buffer)
    y cambiar sus propiedades

    Si ese es el orden de hacer las cosas, hay espacio para mejorar. Primero crear todas las etiquetas, cambiar sus propiedades, y cuando todos estén listos, añadir al panel: Panel.Controls.AddRange(Control[])

    La mayoría de las veces, todo lo que hacemos es dibujar
    las esquinas redondeadas y agregar gradiente
    para el fondo

    Están haciendo la misma cosa una y otra vez? ¿Cómo son sus gradientes generados? La escritura de una imagen no puede ser tan lento. Una vez tuve que crear un 1680×1050 gradiente en la memoria, y fue muy rápido, como, demasiado rápido para Stopwatch, por lo que el dibujo de un gradiente no puede ser tan difícil.

    Mi consejo sería intentar y caché de algunas cosas. Abierto Pintar, dibujar sus esquinas y guardar en el disco, o generar una imagen en memoria una sola vez. Luego de la carga (y cambiar de tamaño), según sea necesario. Mismo para el degradado.

    Incluso si los diferentes botones de diferentes colores, pero el mismo motivo, puede crear un mapa de bits con la Pintura o lo que sea y en tiempo de ejecución de la carga y de la multiplicación de los valores de Color por otro Color.

    EDICIÓN:

    si nos suspendlayout del panel antes de la
    bucle y reanudar el diseño del panel cuando el lazo es más

    Que no es lo SuspendLayout y ResumeLayout se para. La suspensión de la lógica de diseño, es decir, el posicionamiento automático de los controles. Más relevantes con controles flowlayoutpanel y TableLayoutPanel.

    Como para doublebuffering, no estoy seguro de que se aplica a la costumbre de sacar el código (no lo he probado). Creo que se debe implementar su propio.

    Doublebuffering en pocas palabras:
    Es muy sencillo, un par de líneas de código. En el evento paint, representar en un mapa de bits en lugar de representar a la Graphics objeto y, a continuación, dibuje el mapa de bits a la Graphics objeto.

    • Si quieres ir por ese camino, tengo un par de ideas más. (Lunes, debido a que el 8 de Mayo es un día de fiesta en Francia)
    • Va a pensar acerca de todo esto. Tres bien 😉 No un día de fiesta en España. Les contaré algo más sobre lo que estoy haciendo, tal vez hay un MONTÓN de espacio para la mejora. 😉 Gracias.
    • Que sugerencia acerca de la creación de todo el Control[] y el establecimiento de una vez con AddRange resuelto mi problema perfectamente. Muchas gracias para los que, como yo no creo que yo hubiera probado que en mi propia durante un buen rato 😉
  4. 4

    Además de la DoubleBuffered de la propiedad, también tratar de agregar esto a su constructor del control:

    SetStyle(ControlStyles.OptimizedDoubleBuffer | 
             ControlStyles.AllPaintingInWmPaint, true);

    Y si que termina no siendo suficiente (que voy a salir en una extremidad y decir que no), considere la posibilidad de tener una mirada en mi respuesta a esta pregunta y suspender/reanudar la actualización del panel o de la Forma. Esto deja a su diseño de operaciones completa, y luego hacer todo el dibujo una vez hecho esto.

    • Nosotros ya estamos haciendo eso, y también ControlStyles.UserPaint; creo que he probado todas las combinaciones posibles. Los resultados son siempre más o menos lo mismo :S
    • Estoy experimentando el mismo comportamiento que el OP de la otra pregunta tiene «no ayuda … también me di cuenta de que cuando la ventana de menús de la superposición de algunos de el botón y la fuerza para volver a dibujar, la actualización es particularmente lenta (por ejemplo, se ven los botones del trazado fronterizo, botón lleno de color sólido, por último botón de muestra, la imagen, a continuación, sigue el siguiente botón)» No sólo es super lento ahora, pero también tiene un borde… es raro :S
    • En el control personalizado código de dibujo están redibujando el control completo cada vez, o sólo la parte que debe ser?
    • Esto parece hacer exactamente lo mismo como la configuración de la DoubleBuffered propiedad de acuerdo a la referencesource.microsoft.com/#System.Windows.Forms/winforms/….
  5. 2

    Suena como lo que usted está buscando es un «compuesto» de la pantalla, donde toda la aplicación se dibujan todos a la vez, casi como un gran mapa de bits. Esto es lo que sucede con las aplicaciones de WPF, excepto el «chrome» en torno a la aplicación (cosas como la barra de título, manejadores de cambio de tamaño y barras de desplazamiento).

    Tenga en cuenta que normalmente, a menos que te hayas metido con algunos de los estilos de ventana, cada control de formularios Windows forms es responsable de la pintura en sí misma. Es decir, cada control obtiene una grieta en el WM_ PINTURA, WM_ NCPAINT, WM_ERASEBKGND, etc pintura relacionadas con los mensajes y se encarga de estos mensajes de forma independiente. Lo que esto significa para usted es que el doble búfer sólo se aplica para el control individual en el que usted está tratando. Para conseguir algo cercano a un lugar limpio, compuesta efecto, usted debe preocuparse no sólo con los controles personalizados que son el dibujo, pero también los controles de contenedor en el que se colocan. Por ejemplo, si usted tiene un Formulario que contiene un Cuadro de grupo que a su vez contiene un número de personalizado dibujado botones, cada uno de estos controles deben tener allí DoubleBuffered de la propiedad se establece en True. Tenga en cuenta que esta propiedad está protegido, así que esto significa que o bien acaban de heredar para los diversos controles (sólo para establecer el doble búfer de propiedad) o utilizar la reflexión para establecer la propiedad protegida. Además, no todos los controles de formularios Windows forms respecto a la DoubleBuffered de la propiedad, como internamente algunos de ellos son sólo contenedores de los nativos «común» de los controles.

    Hay una forma de establecer un compuesto de la bandera si usted está apuntando a Windows XP (y, presumiblemente, más adelante). No es la WS_ EX_ COMPUESTA estilo de ventana. Yo la he utilizado antes de mezclar los resultados. No funciona bien con WPF/WinForm aplicaciones híbridas, y también no juega bien con el control DataGridView. Si usted va esta ruta, asegúrese de hacer un montón de pruebas en máquinas diferentes, porque he visto a resultados extraños. Al final, he abandonado utilizado de este enfoque.

    • Me he divertido con este juego de la bandera, pero al final no pude evitar un error que podría causar un núcleo de la CPU a la vuelta de hasta el 100% y la estancia allí de cualquier forma con las pestañas abiertas.
  6. 2

    Tal vez dibuja por primera vez en un control-sólo ‘visible’ (privado) de búfer y, a continuación, un render:

    En su control

    BufferedGraphicsContext gfxManager;
    BufferedGraphics gfxBuffer;
    Graphics gfx;

    Una función para instalar gráficos

    private void InstallGFX(bool forceInstall)
    {
        if (forceInstall || gfxManager == null)
        {
            gfxManager = BufferedGraphicsManager.Current;
            gfxBuffer = gfxManager.Allocate(this.CreateGraphics(), new Rectangle(0, 0, Width, Height));
            gfx = gfxBuffer.Graphics;
        }
    }

    En su método paint

    protected override void OnPaint(PaintEventArgs e)
    {
        InstallGFX(false);
        //.. use GFX to draw
        gfxBuffer.Render(e.Graphics);
    }

    En su método resize

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        InstallGFX(true); //To reallocate drawing space of new size
    }

    El código anterior ha sido algo probado.

  7. 0

    Tuve el mismo problema con un tablelayoutpanel al cambiar de controles que quería muestran.

    Estoy completamente de deshice de el parpadeo, la creación de una clase que hereda de la tabla, a continuación, habilitado doublebuffering.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    
    namespace myNameSpace.Forms.UserControls
    {
        public class TableLayoutPanelNoFlicker : TableLayoutPanel
        {
            public TableLayoutPanelNoFlicker()
            {
                this.DoubleBuffered = true;
            }
        }
    }
  8. 0

    He tenido un montón de problemas similares en el pasado, y la forma en que lo resolvió fue el uso de una tercera parte de interfaz de usuario de la suite (que es, DevExpress) en lugar de la estándar de los controles de Microsoft.

    Empecé con los controles estándar de Microsoft, pero me di cuenta de que estaba constantemente problemas de depuración que fueron causadas por sus controles. El problema se complica por el hecho de que Microsoft no suele solucionar ninguno de los problemas que se identifican y hacen muy poco para dotar de adecuadas soluciones.

    Me cambié a DevExpress, y no tengo nada más que cosas buenas que decir. El producto es sólido, que proporcionan un gran soporte y documentación, y sí que realmente escuchar a sus clientes. En cualquier momento que yo tenía una pregunta o un problema, tengo una amable respuesta dentro de 24 horas. En un par de casos, encontré un bug y en ambos casos, se implementó una solución para la próxima versión de servicio.

    • Gracias Dennis, me encantaría cambiar a algo como eso, pero usamos una costumbre dibujado interfaz de usuario («único») que es la marca de nuestra aplicación. El cambio a «otro conjunto de Controles de Windows» no va a hacer por nosotros. Nuestra interfaz es táctil, orientada a + tablet pc, por lo que sólo el uso de «unos» controles de WinCtl, pero casi siempre personalizadas de dibujo en la parte superior de eso.
    • hicimos lo mismo aquí. Mala elección, creo. Estamos buscando a mejorar para WPF, pero es un montón de trabajo….
    • sí, el cambio de esta aplicación WPF meses de trabajo! o más! :S
  9. 0

    He visto mal en winforms parpadeo en los formularios donde los controles se refiere a la falta de una fuente.

    Esto probablemente no es común, pero es que vale la pena considerar si usted ha intentado todo lo demás.

Dejar respuesta

Please enter your comment!
Please enter your name here