2010-07-26 24 views
7

Esto es realmente simple..Net TableLayoutPanel - Borrar controles es muy lento

Tengo un TableLayoutPanel que está lleno de controles (solo Etiquetas, Botones y algunos Paneles con botones) basados ​​en una consulta de base de datos. Cuando los datos deben actualizarse, utilizo TableLayoutPanel.Controls.Clear(). Desafortunadamente, esta es una operación muy lenta. Esperaría que fuera más rápido que el código que llena la tabla, pero es al menos 3 o 4 veces más lento.

Demuestré definitivamente que la lentitud se produce al ejecutar Controls.Clear() al ejecutar esto como lo único que se hace al TableLayoutPanel después de que se muestre un cuadro de mensaje (luego el procedimiento retorna). Los controles desaparecen visiblemente de abajo hacia arriba. Cuando el conjunto de registros se utiliza para volver a llenar el TableLayoutPanel, la velocidad de los controles que aparecen de arriba a abajo es casi más rápida de lo que puedo ver.

Ya estoy haciendo TableLayoutPanel.SuspendLayout() y ResumeLayout().

El uso de this.DoubleBuffered = true en el formulario no parece hacer nada.

Podría deshacerme de todo el control y volver a crearlo a través del código, pero esto es un gran problema y hace que tener una bonita GUI de diseñador de formularios no tenga sentido. Tendría que profundizar en cada propiedad que he establecido en el control y crear una línea de código para ello (aunque creo que podría sacar esto del código de diseñador en sí, todavía se siente mal).

¿Alguna idea sobre cómo hacer el trabajo más rápido? Incluso estoy abierto a usar otros métodos además de TableLayoutPanel ... Solo necesito libertad para poner varios botones por celda o excluir eso para poder abarcar columnas en el encabezado de la tabla.

¿Puede C# congelar al menos la forma completa mientras se vuelve a dibujar y luego pintar todo a la vez?

+0

Mencionas TableLayoutPanel y FlowLayoutPanel. –

+0

¿Ha ejecutado un generador de perfiles para probar que es exactamente esa línea de código? ¿Es posible que cause efectos secundarios con esta línea de código? ¿Se están convocando eventos para que los controles se hagan invisibles o similares? – WillfulWizard

+0

@Willfulwizard Actualicé mi publicación con el motivo por el que creo que es el Controls.Clear() que lleva mucho tiempo. – ErikE

Respuesta

9

He tenido problemas con la lentitud al usar TableLayoutPanels también.En lugar de establecer la propiedad DoubleBuffered en el formulario, la mejor solución que he encontrado es crear una nueva clase que hereda de TableLayoutPanel, y en esa clase constructor, habilitar el búfer doble:

public class DoubleBufferedTableLayoutPanel : TableLayoutPanel 
{ 
    public DoubleBufferedTableLayoutPanel() 
    { 
     DoubleBuffered = true; 
    } 
} 

A continuación, utilice el DoubleBufferedTableLayoutPanel donde normalmente usaría un TableLayoutPanel.

+0

¿Podrías especular sobre por qué crees que es? El TableLayoutPanel tiene una propiedad DoubleBuffered, ¿por qué no solo establecerlo en el momento del diseño (supongo que esto no funciona)? Entonces, ¿cuál es el problema? – ErikE

+1

En la versión de .NET que estoy usando (2008, SP1), ni la barra de herramientas Propiedades ni Intellisense enumeran la propiedad DoubleBuffered para TableLayoutPanels. Si tiene una instancia de TableLayoutPanel, diga myTableLayoutPanel e intente establecer myTableLayoutPanel.DoubleBuffered = true, el compilador mostrará un error "No se puede acceder al miembro protegido 'System.Windows.Forms.Control.DoubleBuffered'". Si su versión de .NET sí ofrece la propiedad DoubleBuffered en el TableLayoutPanel ordinario, entonces me imagino que establecerlo allí funcionaría bien. –

+0

Tengo que decir que nunca esperé tener que hacer este tipo de ajustes y mucho menos tener un impacto en el rendimiento de una manera tan asombrosamente positiva. ¡Cosas ordenadas! – xDisruptor

0

Si voy a crear una interfaz gráfica de usuario dinámica, siempre lo haré en el código. Pero en un punto de partida, simplemente empiezo con el diseñador en una forma ficticia y le doy estilo a cada control de la manera que me gusta (o mejor al cliente). Después me eche un vistazo en el archivo Designer.cs y copiar la configuración de las propiedades necesarias de ella en alguna función de fábrica como

private TextBox CreateTextBox(string name, /* maybe other parameters */) 
{ 
    var textBox = new TextBox(); 
    textBox.Name = name; 
    //Other settings from given parameters... 

    //Further settings which are all the same for these kind of control 
    textBox.KeyDown += (sender, e) => {}; 

    return textBox; 
} 

Así me aseguro de que todos los controles se siente y se ve igual en mi interfaz gráfica de usuario. Esto se hará en cada nivel dentro de mi superficie (comenzando con los controles pequeños como TextBox y va hasta los contenedores como GroupBox o TableLayoutPanel.

En algunos casos, esto conduce a un punto en el que una función de fábrica llama varias otras funciones de fábrica . Si esto se está convirtiendo en realidad es el momento de pensar en la encapsulación de estos controles en una sola UserControl, pero como siempre depende si esto es necesario o no.

por mi parte sólo puedo alentar a mover el código a cabo del diseñador en una función auto escrita. Al principio es (como siempre) más trabajo, pero luego es más fácil hacer cha aún más grande nges al diseño.

3

Esto parece funcionar para mis usos:

tableLayoutPanel.Visible = false; 
tableLayoutPanel.Clear(); 
/* Add components to it */ 
tableLayoutPanel.Visible = true; 
3

No hay necesidad de subclase TableLayoutPanel como en Chris Ryan's answer. Tuve el mismo problema y lo resolví estableciendo la propiedad a través de la reflexión:

typeof(TableLayoutPanel) 
    .GetProperty("DoubleBuffered", 
     System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) 
    .SetValue(myTableLayoutPanel, true, null);