Динамически заполняемое снижение производительности TableLayoutPanel

StackOverflow https://stackoverflow.com/questions/678805

Вопрос

У меня есть пользовательский элемент управления, который содержит TableLayoutPanel с двумя столбцами и принимает команды для динамического добавления строк для отображения сведений об элементе, выбранном в отдельном элементе управления.Таким образом, пользователь выберет строку в другом элементе управления (DataGridView), а в обработчике событий SelectedItemChanged для DataGridView я очищаю элемент управления подробностями, а затем восстанавливаю все строки для нового выбранного элемента (который может иметь совершенно другую детализацию). отображение ранее выбранного элемента).Это прекрасно работает какое-то время.Но если я продолжаю переходить от одного выбранного элемента к другому в течение довольно долгого времени, обновления становятся ОЧЕНЬ медленными (по 3-5 секунд каждое).Это звучит так, будто я не все распределяю должным образом, но я не могу понять, чего мне не хватает.Вот мой код для очистки 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();
}

И как только я закончу загрузку всех нужных элементов управления в TableLayoutPanel для следующего подробного отображения, я называю это:

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

Я не использую ничего, кроме меток (и очень редко TextBox) внутри TableLayoutPanel, и добавляю метки и текстовые поля в список элементов управления (на который есть ссылка в DisposeAndClearControls()), когда я их создаю.Я попробовал просто перебрать DetailTable.Controls и разместить их таким образом, но, похоже, половина элементов управления пропущена (определяется путем пошагового прохождения через них в отладчике).Таким образом, я знаю, что получу их всех.

Мне были бы интересны любые предложения по улучшению производительности отрисовки, но особенно то, что вызывает ухудшение качества при выборе нескольких вариантов выбора.

Это было полезно?

Решение 3

Я изменил содержащую форму, чтобы просто создавать новую версию пользовательского элемента управления при каждом изменении выбора.Он избавляется от старого и строит новый.Кажется, это работает просто отлично.В любом случае, изначально я решил повторно использовать только один из соображений производительности.Понятно, что это не улучшает производительность.И производительность не станет проблемой, если я удалю старый и создам новый.

К сожалению, TableLayoutPanel протекает вот так.

Другие советы

Просто используйте пользовательский элемент управления, который наследуется от TableLayoutPanel, и установите для свойства DoubleBuffered значение true, отлично работает...особенно когда вы динамически добавляете или удаляете строки.

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

У меня была аналогичная проблема с TableLayout.Если бы я использовал TableLayout.Controls.Clear() метод, дочерние элементы управления так и не были удалены, но когда я просто удалил TableLayout, не очищая его, утечка прекратилась.Оглядываясь назад, можно сказать, что забавно, что я использовал метод Clear, чтобы предотвращать какая-то утечка.

По-видимому, метод Clear не удаляет элементы управления явно (что имеет смысл, поскольку тот факт, что вы удалили их из TableLayout, не означает, что вы закончили с ними), а удаление дочерних элементов управления из TableLayout не позволяет процедуре очистки удалить их. дочерние элементы, когда удаляется сам LayoutTable (о них он просто больше не знает).

Моя рекомендация:Удалить DetailTable.Controls.Clear(); строку, удалите сам DetailTable из родительского Элементы управления коллекцию и утилизируйте ее, а затем создайте новый TableLayout для следующего раунда.Также полностью потеряйте метод DisposeAndClearControls, поскольку он вам не понадобится.По моему опыту, это сработало хорошо.

Таким образом, вам больше не придется перерабатывать весь пользовательский элемент управления, а только внутренний TableLayout.

Я столкнулся с той же проблемой и нашел хороший способ, не меняя слишком много:

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

или в С#:

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

К сожалению, единственный совет, который я могу дать, — это позаботиться о размещении элементов управления самостоятельно.По моему опыту, .NET TableLayoutPanel, хотя и очень полезна, пропускает ЧТО-ТО и становится неприемлемо медленной по мере роста (и для достижения этой точки не требуется слишком много ячеек).Такое поведение можно увидеть и в дизайнере.

TableLayoutPanel.Controls.Clear() у меня работает нормально, возможно, это потому, что я удаляю его с другой вкладки, чем она отображается.

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

foreach (Control control in controls)
{
    control.Dispose();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top