Pregunta

Tengo un control de usuario que contiene un 2-columna TableLayoutPanel y acepta comandos para añadir dinámicamente filas para mostrar detalles de un elemento seleccionado en un control separado. Por lo tanto, el usuario seleccionará una fila en el otro control (un DataGridView), y en el controlador de eventos SelectedItemChanged para el DataGridView que borrar el control de detalle y luego regenerar todas las filas para el nuevo elemento seleccionado (que puede tener un detalle totalmente diferente visualización desde el elemento seleccionado previamente). Esto funciona muy bien por un tiempo. Pero si sigo pasar de un elemento seleccionado a otro desde hace mucho tiempo, las actualizaciones se hacen muy lento (3-5 segundos cada uno). Eso hace que suene como si no estuviera desechar todo correctamente, pero no puedo imaginar lo que me falta. Aquí está mi código para despejar el TableLayoutPanel:

private readonly List<Control> controls;

public void Clear()
{
    detailTable.Visible = false;
    detailTable.SuspendLayout();
    SuspendLayout();
    detailTable.RowStyles.Clear();
    detailTable.Controls.Clear();
    DisposeAndClearControls();
    detailTable.RowCount = 0;
    detailTable.ColumnCount = 2;
}

private void DisposeAndClearControls()
{
    foreach (Control control in controls)
    {
        control.Dispose();
    }
    controls.Clear();
}

Y una vez que consiga terminado de cargar todos los controles que quiero en el TableLayoutPanel para la siguiente pantalla detalle aquí es lo que llamo:

public void Render()
{
    detailTable.ResumeLayout(false);
    detailTable.PerformLayout();
    ResumeLayout(false);
    detailTable.Visible = true;
}

No estoy usando nada más que etiquetas (y un cuadro de texto en muy raras ocasiones) en el interior del TableLayoutPanel, y añadir las etiquetas y cuadros de texto a la lista de controles (se hace referencia en DisposeAndClearControls ()) cuando los creo. He intentado simplemente interactuando sobre detailTable.Controls y les disponer de esa manera, pero parecía perderse la mitad de los controles (determinados por pisar a través de él en el depurador). De esta manera sé que a todos consigo.

Yo estaría interesado en cualquier sugerencia para mejorar el rendimiento del dibujo, pero sobre todo lo que está causando la degradación a través de múltiples selecciones.

¿Fue útil?

Solución 3

He cambiado el formulario que contiene sólo la construcción de una nueva versión de mi control de usuario en cada cambio de selección. Dispone el viejo y construye una nueva. Esto parece funcionar muy bien. Yo había ido con la reutilización originalmente sólo uno por razones de rendimiento de todos modos. Es evidente que no mejora el rendimiento. Y el rendimiento no es un problema si puedo desechar el viejo y crear uno nuevo.

Lamentable que las fugas TableLayoutPanel así, sin embargo.

Otros consejos

Sólo tiene que utilizar un control personalizado que hereda de TableLayoutPanel y establezca la propiedad DoubleBuffered en verdad, funciona muy bien ... sobre todo cuando se agrega de forma dinámica o eliminar filas.

public CustomLayout()
{
   this.DoubleBuffered = true;
   InitializeComponent();
}

he tenido un problema similar con TableLayout. Si usara TableLayout.Controls.Clear () método, el niño nunca controla consiguió dispuesto pero cuando simplemente caer el TableLayout sin borrar ella, la fuga se detuvo. En retrospectiva, es gracioso He utilizado el método Clear a evitar algún tipo de fuga.

Al parecer, el método transparente no se disponga explícitamente de los controles (que tiene sentido, ya que el hecho de que se les retire de la TableLayout no significa que haya terminado con ellos) y la eliminación de los controles secundarios de la TableLayout evita la rutina de limpieza para disponer de los niños cuando la propia LayoutTable se dispone (que simplemente no sabe nada de ellos nunca más).

Mi recomendación: Eliminar la detailTable.Controls.Clear (); línea, retire la propia detailTable a partir de la matriz Controles recolección y disponer que, a continuación, crear una marca nueva TableLayout para la siguiente ronda. También perderá el método DisposeAndClearControls por completo, ya que no lo necesitará. En mi experiencia, funcionó muy bien.

De esta manera, usted no tendrá que reciclar todo el control de usuario más, pero sólo el TableLayout dentro.

Me enfrenté al mismo problema y encontró una buena forma sin cambiar demasiado:

en VB.net

Dim tp As Type = tlpMyPanel.GetType().BaseType
Dim pi As Reflection.PropertyInfo = _
    tp.GetProperty("DoubleBuffered", _ 
    Reflection.BindingFlags.Instance _
    Or Reflection.BindingFlags.NonPublic)
pi.SetValue(tlpMyPanel, True, Nothing)

o en C #:

Type tp = tlpMyPanel.GetType().BaseType;
System.Reflection.PropertyInfo pi = 
    tp.GetProperty("DoubleBuffered",
    System.Reflection.BindingFlags.Instance 
    | System.Reflection.BindingFlags.NonPublic);
pi.SetValue(tlpMyPanel, true, null);

Por desgracia, el único consejo que puedo ofrecer es cuidar de la colocación de los controles usted mismo. En mi experiencia .NET TableLayoutPanel, si bien es muy útil, se está escapando algo y se convierte en unusably lenta a medida que crece (y no hace falta ser un número excesivo de las células para llegar a este punto, tampoco). Este comportamiento se puede ver en el diseñador también.

TableLayoutPanel.Controls.Clear () funciona bien para mí, tal vez su porque borrarlo de una pestaña diferente a la que aparece en su.

List<Control> controls = new List<Control>();
foreach (Control control in tableLayoutPanelEnderecoDetalhes.Controls)
{
    controls.Add(control);
}

foreach (Control control in controls)
{
    control.Dispose();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top