2009-04-22 54 views
26

Tengo un Windows Form (C# .NET 3.5) con una serie de botones y otros controles, todos asignados a un panel superior que abarca todo el formulario. Por ejemplo, la jerarquía es: Formulario -> Panel -> otros controles.Windows Forms: utilizando BackgroundImage ralentiza el dibujo de los controles del formulario

Tan pronto como asigne una Imagen de Fondo al Panel, los controles dibujan muy lentamente. Tengo el mismo efecto si utilizo la propiedad BackgroundImage del Formulario y establezco BackgroundColor del Panel como "transparente". Parece que la ventana con el fondo se dibuja primero, luego cada control se agrega uno a uno con un ligero retraso antes de dibujar el siguiente. En otras palabras, puede seguir el orden en que cada control se dibuja en el formulario. Una vez que se han dibujado todos los controles una vez que este efecto ya no ocurre, la capacidad de respuesta del formulario es aún lenta.

En el diseñador de Visual Studio obtengo el mismo efecto, especialmente notable cuando muevo los controles alrededor. A veces, el dibujo del formulario se detiene por completo durante uno o dos segundos, lo que hace que trabajar con BackgroundImage sea un arrastre total, tanto en el diseñador como en la aplicación resultante.

Por supuesto, traté de usar DoubleBuffered = true, y también lo configuré en todos los controles usando reflexión, sin ningún efecto.

Además, aquí está el código de carga de formularios porque es un poco inusual. Copia todos los controles de otra forma en el formulario actual. Esto se hace para poder editar el aspecto visual de cada pantalla por separado utilizando el diseñador mientras se comparte una forma común y una base de código común. Tengo la corazonada de que puede ser la causa de las ralentizaciones, pero aún no explica por qué las ralentizaciones ya son evidentes en el diseñador.

private void LoadControls(Form form) 
{ 
    this.SuspendLayout(); 

    this.DoubleBuffered = true; 
    EnableDoubleBuffering(this.Controls); 

    this.BackgroundImage = form.BackgroundImage; 
    this.BackColor = form.BackColor; 

    this.Controls.Clear(); 
    foreach (Control c in form.Controls) 
    { 
     this.Controls.Add(c); 
    } 

    this.ResumeLayout(); 
} 

Como se puede ver, SuspendLayout() y ResumeLayout() se utilizan para evitar volver a dibujar innecesario.

Aún así, la forma es "lenta como el infierno" una vez que se utiliza una imagen de fondo. Incluso traté de convertirlo a PNG, JPG y BMP para ver si eso marca alguna diferencia. Además, la imagen tiene un tamaño de 1024x768, pero las imágenes más pequeñas tienen el mismo efecto de desaceleración (aunque un poco menos).

¿Qué debo hacer?

+0

Si está utilizando una versión de VS con el generador de perfiles incluido, ¿dónde dice el perfilador que está gastando todo su tiempo? –

+0

posible duplicado de [Cómo corregir el parpadeo en los controles de usuario] (http://stackoverflow.com/questions/2612487/how-to-fix-the-flickering-in-user-controls) –

Respuesta

36

SuspendLayout() y ResumeLayout() no suspender el dibujo, solo las operaciones de diseño. Dar a este chico un tiro:

public static class ControlHelper 
{ 
    #region Redraw Suspend/Resume 
    [DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] 
    private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 
    private const int WM_SETREDRAW = 0xB; 

    public static void SuspendDrawing(this Control target) 
    { 
     SendMessage(target.Handle, WM_SETREDRAW, 0, 0); 
    } 

    public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); } 
    public static void ResumeDrawing(this Control target, bool redraw) 
    { 
     SendMessage(target.Handle, WM_SETREDRAW, 1, 0); 

     if (redraw) 
     { 
      target.Refresh(); 
     } 
    } 
    #endregion 
} 

uso debe ser bastante explica por sí mismo, y la sintaxis es idéntica a SuspendLayout() y ResumeLayout(). Estos son métodos de extensión que se mostrarán en cualquier instancia de Control.

+0

no ayudó. .. también noté que cuando los menús emergentes superponen algunos de los botones y los obligan a redibujar, el redibujado es particularmente lento (por ejemplo, ves los botones borde dibujado, botón lleno de color sólido, finalmente el botón dibuja su imagen, luego sigue el siguiente botón). – steffenj

+0

¡Esto realmente me dio un gran aumento en el rendimiento! Tenía alrededor de 60 etiquetas en un solo control, colocadas en un panel de diseño de tabla. Las columnas se configuraron para cambiar el tamaño automáticamente, lo que demoró mucho tiempo en volver a generar. Este truco parece suspender el dibujo, hasta que el diseño esté completo, eliminando el molesto redibujado visible. – Siewers

+0

Esto hizo una gran diferencia para mi user_control también. ¡Gracias! –

1

Para mí, el puesto Form load is slow if adding a background image resuelto el problema:

Asegúrese de que su backgroundColor no está ajustado a 'transparente'. Configúrelo en 'blanco' para un mejor rendimiento.

También, haga BackgroundImageLayout para ser 'Center' o 'Stretch' para aumentar el rendimiento. Esto habilitará el doble buffer en el formulario.

+0

A pesar de que mi formulario tenía un tamaño fijo para que coincida con el tamaño de la imagen, el valor por defecto de BackgroundImageLayout of Tile fue el culpable. Cambió para estirar y solucionó el problema. – Tim

3

También enfrenté el mismo problema y pude resolverlo reduciendo la resolución de la imagen de fondo.Cuando utiliza imágenes de gran tamaño (p. Ej .: 1280X800) como fondo, tomará tiempo dibujar controles en el formulario. Es mejor abrir la imagen en tamaño 'Paint' que más pequeña que su formulario y luego guardar en formato 'bmp'. Ahora intenta agregar esta imagen como fondo de tu formulario.

+0

He intentado tantas cosas. Y como último, quería dar una oportunidad y, sorprendentemente, funcionó para mí. Diferencia significativa ... Gracias – curiousBoy

2

Otra forma muy simple de evitar los redibujados permanentes al agregar los controles es hacer que el control primario sea invisible antes de agregarle controles. Posteriormente, usted hace que el control principal (por ejemplo, un panel) sea visible y allí está sin todos los repintados. :-)

panelParent.visible = false; 

for(...) { 
    // Add your controls here: 
    panelParent.Controls.Add(...); 
} 

panelParent.visible = true; 
1

Soy consciente de que es un viejo hilo, pero he encontrado que durante la búsqueda de información sobre el mismo tema, por lo que en caso de que sea útil a alguien, en algún momento:

Mi situación: tienen una grilla de paneles de 13 x 12, que tienen una imagen de fondo configurada dinámicamente y cambiada regularmente, según las selecciones de los usuarios. Cada Panel también tiene un control de etiqueta de texto agregado. Para que el texto se superponga a la imagen de fondo, tiene que establecerse en Transparente (por cierto, mi experiencia fue que BackgroundImageLayout de Zoom, Stretch, Center tuvo poco o ningún efecto. BackColor establecido en transparente o blanco también tuvo poco efecto).

Cada dibujo de la grilla de paneles (incluido el cambio de tamaño) tardaba aproximadamente un segundo, no está mal, pero es muy visible, y un problema de usabilidad en máquinas más lentas.

Mis imágenes no eran enormes, pero sí algo grandes.

Lo que encontré: Al cambiar el tamaño de mi conjunto de imágenes al tamaño de panel exacto antes de establecer la imagen de fondo, el tiempo de dibujo disminuyó drásticamente, en algún momento alrededor de 0,1 segundos. Como mi programa cambia el tamaño de los paneles según el tamaño de la ventana, cambio el tamaño del conjunto de imágenes de forma dinámica en el evento de redimensionamiento de Windows antes de configurar el fondo de los 156 paneles.

En retrospectiva, es una optimización obvia ... cambiar el tamaño de 8 imágenes una vez en lugar de repetidas veces 156 veces.

1

Resolví el mismo problema usando PictureBox. Simplemente agregue PictureBox a su contenedor, elija "Móntelo en el contenedor principal" (o propiedad Dock = Fill) y configure su Imagen. Se verá igual que BackGroundImage del control principal.

Cuestiones relacionadas