天道酬勤,学无止境

.Net TableLayoutPanel – Clearing Controls is Very Slow

This is really simple.

I have a TableLayoutPanel that is populated with controls (just Labels, Buttons, and some Panels with buttons) based on a database query. When the data needs to be refreshed, I use TableLayoutPanel.Controls.Clear(). Unfortunately, this is a very slow operation. I would expect it to be faster than the code populating the table, but it is at least 3 or 4 times slower.

I definitively proved that the slowness is when executing Controls.Clear() by executing this as the single thing done to the TableLayoutPanel after a message box is displayed (then the procedure returns). The controls visibly disappear from the bottom up. When the recordset is used to repopulate the TableLayoutPanel, the speed of the controls appearing from top to bottom is almost faster than I can see.

I'm already doing TableLayoutPanel.SuspendLayout() and ResumeLayout().

Using this.DoubleBuffered = true on the form doesn't appear to do anything.

I could just Dispose the entire control and recreate it through code, but this is a big pain and makes having a nice form designer GUI pointless. I would have to dig into every property I've set on the control and create a line of code for it (though I guess I could get this out of the designer code itself, it still feels wrong).

Any ideas on how to do the job faster? I'm even open to using other methods besides a TableLayoutPanel... I just need the freedom to put multiple buttons per cell or barring that to be able to span columns in the table header.

Can C# at least freeze the whole form while it redraws and then paint all at once?

评论

I've run into issues with slowness using TableLayoutPanels as well. Rather than setting the DoubleBuffered property on the form, the best solution I have found is to create a new class that inherits from TableLayoutPanel, and in that class' constructor, enable double-buffering:

public class DoubleBufferedTableLayoutPanel : TableLayoutPanel
{
    public DoubleBufferedTableLayoutPanel()
    {
        DoubleBuffered = true;
    }
}

Then, use the DoubleBufferedTableLayoutPanel wherever you would normally use a TableLayoutPanel.

This seems to work for my uses:

tableLayoutPanel.Visible = false;
tableLayoutPanel.Clear();
/* Add components to it */
tableLayoutPanel.Visible = true;

There is no need to subclass TableLayoutPanel as in Chris Ryan's answer. I had the same problem and solved it by setting the property through reflection:

typeof(TableLayoutPanel)
   .GetProperty("DoubleBuffered",
      System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
   .SetValue(myTableLayoutPanel, true, null);

If i'm going to built up some dynamic gui i'm always going to do so in code. But at a starting point i just start with the designer on a dummy form and style each control the way i (or better the customer) like(s). Afterwards i take a look into the Designer.cs file and copy the necessary property settings out of it into some factory function like

private TextBox CreateTextBox(string name, /* maybe other parameters */)
{
    var textBox = new TextBox();
    textBox.Name = name;
    //Other settings from given parameters...

    //Further settings which are all the same for these kind of control
    textBox.KeyDown += (sender, e) => {};

    return textBox;
}

So i make sure that every control feels and looks the same on my GUI. This will be done on each level within my surface (starting with the small controls like TextBox and goes up to the containers like GroupBox or TableLayoutPanel.

In some cases this leads to a point where a factory function calls several other factory functions. If this is becoming true it's time to think about encapsulating these controls into a single UserControl, but as always it depends if this is needed or not.

From my side i can only encourage you to move your code out of the designer into a self-written function. At the beginning it is (as always) more work, but afterwards it is easier to make even bigger changes to the layout.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • TableLayoutPanel responds very slowly to events
    In my application I really needed to place a lot of controls (label, textbox, domainupdown) in a nice order. So I went ahead and used some nested TableLayoutPanel. The problem now is, this form responds very slow to most of events (resize, maximize, minimize and ...) it takes really up to 5 seconds for controls within the tables to get resized, redrawed to the new size of form. I am putting a finger in my eye now! If this form is that slow on my home PC (i7@4GHz and a good graphic card) what it will do tommorow on the old P4 computer at work? I even tried to use the code below but it does
  • Winforms TableLayoutPanel以编程方式添加行(Winforms TableLayoutPanel adding rows programmatically)
    问题 我已经为此进行了一段时间的战斗,并且发现许多其他人也为TableLayoutPanel(.net 2.0 Winforms)感到挣扎。 问题 我正在尝试采用“空白” tablelayoutpanel,其中定义了10列,然后在运行时以编程方式添加控件行(即,每个单元格一个控件)。 可能有人以为它应该像 myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */); 但这(对我而言)不会添加行。 所以也许添加一个行样式 myTableLayoutPanel.RowStyles.Clear(); myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F)); 但这也不起作用。 我进行了挖掘,发现myTableLayoutPanel.RowCount用法在设计时间与运行时间之间发生了变化,因此进行了myTableLayoutPanel.RowCount++; 实际上并没有添加另一行,甚至没有为它添加RowStyle条目之前/之后! 我遇到的另一个相关问题是控件将被添加到显示中,但是它们都只是在TableLayoutPanel的0,0点处呈现,此外
  • 在TableLayoutPanel中动态添加行(Add Row Dynamically in TableLayoutPanel)
    问题 我想在c#的Windows窗体的TableLayoutPanel中逐行动态添加这些条目 我怎样才能做到这一点? 回答1 试试下面的代码, // TableLayoutPanel Initialization TableLayoutPanel panel = new TableLayoutPanel(); panel.ColumnCount = 3; panel.RowCount = 1; panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F)); panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F)); panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F)); panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F)); panel.Controls.Add(new Label() { Text = "Address" }, 1, 0); panel.Controls.Add(new Label() { Text = "Contact No" }, 2, 0); panel.Controls.Add(new
  • Need a very customized large Winforms grid
    I am about to develop a Windows PC application (it can be WinForms or WPF) and my main concern is a UI problem I will have to address. Basically, I need to have a grid of about 50x50 that I need to get input from the user for. That's 2500 fields. Realistically most will be left blank, about 10% will be filled out by a user. Each field can be blank or have a number from 1 to 4. I want easy input - a drop down box perhaps (since it doesn't make sense to tab through all 2500 fields when with the keyboard, I want the user to fill out the values with the mouse). I was thinking the drop down boxes
  • 如何在Winforms设计器中访问继承的控件(How to access inherited controls in the winforms designer)
    问题 我正在制作一些控件,这些控件必须具有相同的外观和一些共同的行为,尽管它们是为不同种类的输入而设计的。 因此,我做了一个继承自UserControl的BaseClass,而我所有的控件都继承自BaseClass。 但是,如果我在设计器中添加了针对BaseClass的控件(如TableLayoutPanel),则在设计继承的类时将无法访问它们。 我看到了TableLayoutPanel,但是即使他是“受保护的”,我也无法通过设计器修改它或将控件放入其中。 我可以通过代码轻松访问它,但是我不想失去使用设计器的能力。 现在,我只是从BaseClass中删除了所有控件,在每个继承的类中添加了布局和所有公共控件,然后使用引用在BaseClass中对其进行操作。 但这一点都不令我满意。 有没有一种方法可以使设计器与继承的受保护成员控件一起使用? 环境:C#、. NET 3.5,Visual Studio 2008 编辑以回答SLaks的建议。 我尝试设置一个属性,尽管我不习惯使用它们,但它似乎不起作用。 这是我尝试的代码: public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } public TableLayoutPanel
  • TableLayoutPanel显示垂直滚动(TableLayoutPanel displays vertical scroll)
    问题 我有TableLayoutPanel用于使用AutoScroll = true动态创建控件。 当我添加新控件时,它工作正常。 但是,当我删除并且所有控件都可见时,垂直滚动是可见的。 一些截图在这里: 预期/正确的滚动可见性: 可见性不正确: 有任何想法吗? 更新:这是一些代码 tableLayoutPanel1.SuspendLayout(); tableLayoutPanel1.RowCount = 0; tableLayoutPanel1.RowStyles.Clear(); tableLayoutPanel1.AutoScroll = true; tableLayoutPanel1.Padding = new Padding(0, 0, SystemInformation.VerticalScrollBarWidth, 0); foreach (var item in objects) { tableLayoutPanel1.RowCount++; tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize)); tableLayoutPanel1.Controls.Add(CreateNewItem(item)); } tableLayoutPanel1.RowCount++
  • TableLayoutPanel displays vertical scroll
    I have TableLayoutPanel for dynamic creation of controls with AutoScroll = true. It's work fine when I add new controls. But when I remove and all controls are visible, vertical scroll is visible. Some screenshots here: Expected/correct scroll visibility: Incorrect visibility: Any ideas? Update: Here is some code tableLayoutPanel1.SuspendLayout(); tableLayoutPanel1.RowCount = 0; tableLayoutPanel1.RowStyles.Clear(); tableLayoutPanel1.AutoScroll = true; tableLayoutPanel1.Padding = new Padding(0, 0, SystemInformation.VerticalScrollBarWidth, 0); foreach (var item in objects) { tableLayoutPanel1
  • Remove Row inside TableLayoutPanel makes a layout problem
    I have a WinForms application that has a TableLayoutPanel; this is the definition code: tableLayoutPanel1 = new TableLayoutPanel(); tableLayoutPanel1.Dock = DockStyle.Fill; tableLayoutPanel1.AutoScroll = true; tableLayoutPanel1.RowCount = users.Count + 1; tableLayoutPanel1.ColumnCount = 1; tableLayoutPanel1.GrowStyle = TableLayoutPanelGrowStyle.FixedSize; tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); foreach (String user in users) { tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 600F)); } tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType
  • How to access inherited controls in the winforms designer
    I'm making some controls which all have to share the same look and some common behavior, although they are meant for different kind of inputs. So I made a BaseClass which inherit from UserControl, and all my controls inherit from BaseClass. However, if i add controls for BaseClass in the designer, such as a TableLayoutPanel, i can't access them when I'm designing the inherited classes. I see the TableLayoutPanel, but even though he is "protected", i can't modify it or put controls in it through the designer. I've no trouble accesing it by code, but i don't want to lose the ability to use the
  • 如何在WinForms中禁用表格面板的水平滚动条(How to disable horizontal scrollbar for table panel in winforms)
    问题 嗨,我有一个tablelayoutpanel,我正在动态地将控件绑定到它。 当项目数超过面板高度时,显然会出现垂直滚动条,这没有问题。 但是同时,即使项目的宽度小于面板的宽度,也会出现水平滚动条。 我该如何预防呢? 回答1 int vertScrollWidth = SystemInformation.VerticalScrollBarWidth; tableLayoutPanel1.Padding = new Padding(0, 0, vertScrollWidth, 0); 回答2 停靠的TableLayoutPanel包含停靠的GroupBoxes和设置为100%宽度的单个Column时,我遇到了这个问题。 我不想为这些设置手动大小-我希望它们随表格一起调整大小。 奇怪的是,将TableLayoutPanel的Right Padding设置为1(而不是滚动条的宽度-如您所料,会留下滚动条大小的间隙)完全解决了该问题。 这是在C#2010 Express,.NET 4,Windows 8中。不知道此合并是否可以在其他变体上使用。 将padding设置为0似乎可以解决IDE中的问题,但是在实际运行时问题仍然存在。 给我闻起来像是TableLayoutPanel中的某种错误……或者也许这只是我拥有的控件和属性的特定组合(这是一个非常复杂的布局)。 回答3
  • 如何在C#中动态调整文本框的大小(How to dynamically resize a textbox in C#)
    问题 我是C#用户界面的新手。 我已经创建了一个窗口,如第一个图像所示。 但是,如果用户拖动窗口并使它变大,我希望它使每个richTextBox随它展开,如第二richTextBox图所示。 例如,使richTextBox4与窗口大小成正比。 任何想法将不胜感激 图片1: 图片2: 回答1 您可以将TableLayoutPanel添加到您的窗体。 默认情况下,此面板有两列和两行。 然后,向每个单元格添加一个TextBox并将每个TextBox的Dock -Property设置为Fill 。 最后一步要做的要么设置Dock ,物业你的TableLayoutPanel来Fill或设置Anchor你的,物业TableLayoutPanel ,以Left | Right | Bottom | Top Left | Right | Bottom | Top Left | Right | Bottom | Top 。 然后,您的面板将与表单一起调整大小。 所有这些步骤都可以由设计人员完成。 回答2 利用TableLayoutControl 。 您可以在该表的每个单元格中拥有一个控件。 现在,在该表上,您可以设置: Dock: Fill Column Width: Percentage or absolute value as per needs Row Height: Percentage
  • 在运行时动态地将控件添加到TableLayoutPanel(Adding controls to TableLayoutPanel dynamically during runtime)
    问题 我有一个从两列零行开始的TableLayoutPanel。 我需要做的是,动态添加一行,并用不同的控件填充这两个列(将是面板)。 在Form1中,我以这种方式创建TableLayout: TableLayoutPanel Table = new TableLayoutPanel(); Table.Location = new Point(10, 40); Table.Size = new Size(620,100); Table.AutoSize = true; Table.Name = "Desk"; Table.ColumnCount = 2; Table.RowCount = 0; Table.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; Table.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.AddRows; this.Controls.Add(Table); 之后,在运行时,我需要多少行,以及是否用面板或某些标签填充它们。 可能在同一行中的左侧是“面板”,右侧是“标签”等。 回答1 使用这样的东西: Table.Controls.Add(new Label { Text = "Type:", Anchor =
  • Adding controls to TableLayoutPanel dynamically during runtime
    I have a TableLayoutPanel starting with two columns and 0 rows. What I need to do is, dynamically adding a row and filling both of the columns with different controls (it will be panels). In Form1 I am creating the TableLayout this way: TableLayoutPanel Table = new TableLayoutPanel(); Table.Location = new Point(10, 40); Table.Size = new Size(620,100); Table.AutoSize = true; Table.Name = "Desk"; Table.ColumnCount = 2; Table.RowCount = 0; Table.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; Table.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.AddRows; this.Controls
  • How to prevent controls visually lagging behind on resize inside TableLayoutPanel?
    I have a layout of medium complexity based on several nested TableLayoutPanels. Resizing the form causes the controls inside the deeper nested tables to visually lag behind the resize. Firstly, this makes them look like they move around while the form is being resized, but worse, the edges of the controls are visibly clipped when they lag enough to leave their allocated table cells. Is there any way to prevent this or is this the best TableLayoutPanel can do? Edit: Having experimented with a bunch of programs I came to the conclusion that lag on resize is a ubiquitous problem. To me, it seems
  • 如何防止控件在 TableLayoutPanel 内调整大小时视觉上滞后?(How to prevent controls visually lagging behind on resize inside TableLayoutPanel?)
    问题 我有一个基于几个嵌套TableLayoutPanel的中等复杂度的布局。 调整表单大小会导致更深层嵌套表格内的控件在视觉上滞后于调整大小。 首先,这使它们看起来像是在调整窗体大小时四处移动,但更糟糕的是,当它们滞后到足以离开分配的表格单元格时,控件的边缘明显被剪裁。 有什么办法可以防止这种情况发生,或者这是TableLayoutPanel可以做的最好的事情吗? 编辑:尝试了一堆程序后,我得出的结论是调整大小滞后是一个普遍存在的问题。 对我来说,似乎每个人都已经辞职了,这是不可避免的,也是可以接受的。 当然,如果它实际上是不可避免的,那么接受它就会容易得多:) 查看您最喜欢的“良好 UI”程序中滞后的最简单方法:通过按住左边界调整它的大小并观察所有右对齐的控件跳来跳去(或者,顶部边界和底部对齐的控件,如状态栏)。 周围都坏了。 如果有人能提供很好的理由说明为什么在使用本机 Windows 控件时这是不可避免的,我会接受这个答案。 另外,如果您发现使用本机控件的程序不受此影响,请说出来,这可能会有所帮助... 回答1 Windows 中本机控件的问题在于每个控件都负责绘制自己,这意味着将位图绘制到屏幕上。 由于容器控件中的每个控件都被调整大小,它所占据的窗口区域变得无效,因此不仅容器中的每个控件都重新绘制,容器本身也必须重新绘制。 此外,调整大小/重绘事件都发生在 UI 线程上
  • Cannot remove spacing between controls in TableLayoutPanel?
    There's some spacing between the Buttons I add to my TableLayoutPanel. I removed the border in the Button and set the Margin and Padding to 0 in the Panel. But I continue getting that spacing. tableLayoutPanel.RowCount is set to 8 and the Rows collection I've added 8 rows with Size Type Absolute. Am I missing something? Here's the code: private void FillSelectLayout() { tableLayoutPanelSelect.Controls.Clear(); tableLayoutPanelSelect.RowStyles.Clear(); tableLayoutPanelSelect.RowCount = 8; for (int i = 0; i < 8; i++) { Button buttonSelector = new Button(); buttonSelector.Height = 64
  • 查找添加到TableLayoutPanel的控件的行索引(Find row index of control added to TableLayoutPanel)
    问题 将控件添加到Windows窗体的TableLayoutPanel中时,我需要采取措施。 我正在处理控件的ParentChanged事件,以了解是否将控件添加到父级(此处为TableLayoutPanel),但是我收到的索引是-1。 TableLayoutPanel t; private void button1_Click(object sender, EventArgs e) { // this.Text = tableLayoutPanel1.Height.ToString(); t = new TableLayoutPanel(); t.Dock = DockStyle.Fill; //t.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; t.AutoSize = true; //t.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; t.RowStyles.Add(new RowStyle(SizeType.AutoSize)); t.RowStyles.Add(new RowStyle(SizeType.AutoSize)); t.ColumnStyles.Add(new ColumnStyle(SizeType
  • 在WinForms应用程序中查找集中控件的首选方法是什么?(What is the preferred way to find focused control in WinForms app?)
    问题 在WinForms中查找当前正在接收用户(键盘)输入的控件的首选/最简单方法是什么? 到目前为止,我已经提出了以下建议: public static Control FindFocusedControl(Control control) { var container = control as ContainerControl; return (null != container ? FindFocusedControl(container.ActiveControl) : control); } 从表单中,可以简单地称为(在.NET 3.5及更高版本中,甚至可以将其定义为表单上的扩展方法)- var focused = FindFocusedControl(this); 这样合适吗 有没有我应该使用的内置方法? 请注意,使用层次结构时,仅对ActiveControl的单个调用是不够的。 想象: Form TableLayoutPanel FlowLayoutPanel TextBox (focused) (formInstance).ActiveControl将返回对TableLayoutPanel的引用,而不是TextBox的引用(因为ActiveControl似乎只返回控件树中的直接活动子级,而我正在寻找叶子控件)。 回答1 如果您已经对Windows
  • 如何使FlowLayoutPanel.AutoSize与FlowBreak一起使用(How to get FlowLayoutPanel.AutoSize to work with FlowBreak)
    问题 我的FlowLayoutPanel有问题,我不知道如何解决。 我将两个FlowLayoutPanels放置在另一个中; 第二个内部触发器内部有3个按钮。 FlowLayoutPanel子级的属性为: FlowDirection = LeftToRight; AutoSize = true; AutoSizeMode = GrowAndShrink; WrapContents = true; 现在,我为每个按钮将FlowBreak属性设置为true,但是我看到的不是我想要的行为,我希望FlowLayoutPanel缩小到按钮的宽度, 不能将FlowDirection更改为UpToDown 。 有人知道为什么AutoSize无法正常工作吗? 这是代码。 // //FlowLayoutPanel1 // this.FlowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.FlowLayoutPanel1.Controls.Add(this.FlowLayoutPanel3); this.FlowLayoutPanel1.Location = new System.Drawing.Point(84, 77); this.FlowLayoutPanel1
  • 在Winforms应用程序中调整主窗体的大小时,如何调整面板的大小? [关闭](How do I resize my panels when resizing the main form in a winforms application? [closed])
    问题 关门了。 这个问题需要更加集中。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使其仅通过编辑此帖子即可将重点放在一个问题上。 6年前关闭。 改善这个问题 如果我的winforms应用程序的用户调整了主窗体的大小,则我希望2个面板也与子控件一起伸展。 我怎样才能做到这一点? 回答1 如果我的winforms应用程序的用户调整了主窗体的大小,则我希望2个面板也与子控件一起伸展。 您是TableLayoutPanel(MSDN)的理想用例。 如果仅缩放面板,则使用Dock和Anchor是合适的。 但是,由于您希望控件能够很好地缩放,因此您处于AutoLayout世界中,并且很有可能处于TableLayoutPanel中。 (顺便说一下,我是对此的忠实拥护者,尽管过度使用会对布局控件产生负面的性能影响。) 有关使用它来配置布局以进行缩放的一些有用链接: 自动版式示例 WinForms AutoLayout基础:TableLayoutPanel 在TableLayoutPanel上进行视频培训 回答2 玩转面板的Dock和Anchor属性。 回答3 您可以使用TableLayoutPanel并将列宽设置为x%,这样可以将屏幕分为2个部分。TableLayoutPanel必须为Dock才能填充所有表单或Anchor。 TableLayoutPanel可以包含其他面板。 或者