我有一个包含2列TableLayoutPanel的用户控件,并接受命令来动态添加行以显示在单独控件中选择的项目的详细信息。因此,用户将在另一个控件(DataGridView)中选择一行,并在DataGridView的SelectedItemChanged事件处理程序中清除详细控件,然后重新生成新选定项的所有行(可能具有完全不同的细节)从先前选择的项目中显示)。这很有用。但是如果我长时间从一个选定的项目移动到另一个项目,刷新变得非常慢(每个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;
}
我在TableLayoutPanel中没有使用任何标签(和很少的TextBox),我在创建它们时将标签和文本框添加到控件列表(在DisposeAndClearControls()中引用)。我尝试迭代detailTable.Controls并以这种方式处理它们,但它似乎错过了一半的控件(通过在调试器中逐步执行它来确定)。这样我知道我得到了所有这些。
我对提高绘图性能的任何建议感兴趣,尤其是导致多种选择降级的原因。
答案 0 :(得分:10)
只需使用继承自TableLayoutPanel的自定义控件并将DoubleBuffered属性设置为true,效果很好......尤其是在动态添加或删除行时。
public CustomLayout()
{
this.DoubleBuffered = true;
InitializeComponent();
}
答案 1 :(得分:4)
我在使用TableLayout时遇到了类似的问题。如果我使用 TableLayout.Controls.Clear()方法,子控件永远不会被处理,但是当我简单地删除TableLayout而不清除它时,泄漏就停止了。回想起来,我使用Clear方法防止某种泄漏很有趣。
显然,Clear方法没有明确处理控件(这是有意义的,因为你从TableLayout中删除它们的事实并不意味着你已经完成它们)并从TableLayout中删除子控件会阻止清理例程当LayoutTable本身被处理时处理孩子(它根本不知道它们)。
我的建议:删除 detailTable.Controls.Clear(); 行,从父级的控件集合中删除detailTable本身并进行处理,然后创建一个全新的TableLayout用于下一轮。完全丢失DisposeAndClearControls方法,因为您不需要它。根据我的经验,它运作良好。
这样,您不必再循环使用整个用户控件了,只需回收其中的TableLayout。
答案 2 :(得分:1)
我更改了包含的表单,以便在每次选择更改时构建一个新版本的用户控件。它处理旧的并构造一个新的。这似乎表现得很好。无论如何,我最初只是出于性能原因重新使用了一个。显然,这并没有改善性能。如果我处理旧的并创建一个新的,性能不是问题。
不幸的是,TableLayoutPanel会像那样泄漏。
答案 3 :(得分:0)
不幸的是,我能提供的唯一建议是自己处理控件的放置。根据我的经验,.NET TableLayoutPanel虽然非常有用,但它正在泄漏SOMETHING并且随着它的增长变得非常缓慢(并且它也不需要不合理数量的单元来达到这一点)。这种行为也可以在设计师身上看到。
答案 4 :(得分:0)
TableLayoutPanel.Controls.Clear()对我来说很好,也许是因为我从不同的标签中清除它而不是它显示的。
答案 5 :(得分:0)
我面临同样的问题,找到了一个好方法,但没有改变太多:
在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);
答案 6 :(得分:0)
List<Control> controls = new List<Control>();
foreach (Control control in tableLayoutPanelEnderecoDetalhes.Controls)
{
controls.Add(control);
}
foreach (Control control in controls)
{
control.Dispose();
}