Pergunta

Eu tenho um controle de usuário que contém um 2-coluna TableLayoutPanel e aceita comandos para adicionar dinamicamente linhas para exibir detalhes de um item selecionado em um controle separado. Assim, o usuário irá selecionar uma linha no outro controle (a DataGridView), e no manipulador de eventos SelectedItemChanged para o DataGridView eu limpar o controle detalhe e, em seguida, regenerar todas as linhas para o novo item selecionado (que pode ter um detalhe totalmente diferente visualizar a partir do item previamente seleccionada). Isso funciona muito bem por um tempo. Mas se eu continuar se movendo de um item selecionado para outro por um longo tempo, as atualizações tornam-se muito lento (3-5 segundos cada). Isso faz parecer que eu não estou descartar tudo corretamente, mas eu não consigo descobrir o que eu estou sentindo falta. Aqui está o meu código para limpar o 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();
}

E uma vez que recebo o carregamento terminado até todos os controles que eu quero para o TableLayoutPanel para a próxima exibição detalhes aqui é o que eu chamo de:

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

Eu não estou usando nada além de rótulos (e um TextBox muito raramente) no interior do TableLayoutPanel, e eu acrescento os rótulos e caixas de texto para a lista de controles (referenciados no DisposeAndClearControls ()) quando eu criá-los. Tentei apenas iteração sobre detailTable.Controls e descartá-los dessa maneira, mas ele parecia perder metade dos controles (determinado pelo percorrendo-lo no depurador). Desta forma, eu sei que eu pegá-los todos.

Eu estaria interessado em alguma sugestão para melhorar o desenho desempenho, mas principalmente o que está causando a degradação ao longo de várias seleções.

Foi útil?

Solução 3

Eu mudei o formulário que contém apenas construir uma nova versão do meu controle de usuário em cada alteração de seleção. Dispõe o antigo e constrói um novo. Isto parece para executar apenas multa. Eu tinha originalmente ido com a reutilização de apenas um por motivos de desempenho de qualquer maneira. Claramente que não melhorar o desempenho. E o desempenho não é um problema se eu descartar o antigo e criar um novo.

lamentável que os vazamentos TableLayoutPanel assim, apesar de tudo.

Outras dicas

Basta usar um controle personalizado que herda de TableLayoutPanel e definir a propriedade DoubleBuffered na verdade, funciona muito bem ... especialmente quando você adicionar dinamicamente ou linhas remover.

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

Eu tive um problema semelhante com TableLayout. Se eu usei TableLayout.Controls.Clear () método, os controles filho nunca chegou dispostos, mas quando eu simplesmente largou o TableLayout sem limpá-lo, o vazamento parou. Em retrospecto, é engraçado Eu usei o método Clear para evitar algum tipo de vazamento.

Aparentemente, Clear método não descartar explicitamente dos controles (o que faz sentido, porque o fato de que você removeu do TableLayout não significa que você é feito com eles) e removendo os controles filho do TableLayout impede que a rotina de limpeza de dispor das crianças quando o próprio LayoutTable fica disposto (ele simplesmente não sabe sobre eles anymore).

A minha recomendação: Elimine o detailTable.Controls.Clear (); linha, remova o próprio detailTable a partir do pai Controles coleta e descarte-o, em seguida, criar uma nova marca TableLayout para a próxima rodada. Também perdem o método DisposeAndClearControls inteiramente desde que você não vai precisar dele. Na minha experiência, isso funcionou muito bem.

Desta forma, você não terá de reciclar seu controle de usuário toda mais, mas apenas o TableLayout dentro.

I enfrentou o mesmo problema e encontrou uma boa maneira sem mudar muito:

no 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)

ou em 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);

Infelizmente, o único conselho que posso dar é para cuidar da colocação de seus controles de si mesmo. Na minha experiência, o .NET TableLayoutPanel, embora muito útil, está vazando alguma coisa e torna-se bastante lento à medida que cresce (e que não tem um número razoável de células para chegar a este ponto, qualquer um). Este comportamento pode ser visto no designer também.

TableLayoutPanel.Controls.Clear () funciona bem para mim, talvez o seu porque eu limpá-la a partir de uma guia diferente do que o seu exibidos na.

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

foreach (Control control in controls)
{
    control.Dispose();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top