Динамическое заполнение снижения производительности TableLayoutPanel - PullRequest
4 голосов
/ 24 марта 2009

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

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

Ответы [ 7 ]

10 голосов
/ 18 июня 2009

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

public CustomLayout()
{
   this.DoubleBuffered = true;
   InitializeComponent();
}
4 голосов
/ 25 февраля 2010

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

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

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

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

1 голос
/ 24 марта 2009

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

Жаль, что TableLayoutPanel протекает так же.

0 голосов
/ 01 апреля 2013
List<Control> controls = new List<Control>();
foreach (Control control in tableLayoutPanelEnderecoDetalhes.Controls)
{
    controls.Add(control);
}

foreach (Control control in controls)
{
    control.Dispose();
}
0 голосов
/ 14 марта 2013

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

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

или в 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);
0 голосов
/ 05 мая 2012

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

0 голосов
/ 24 марта 2009

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

...