8

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 absoloutly nothing, if it is not slowing it down more!

private void FilterForm_ResizeBegin(object sender, EventArgs e)
{
    foreach(TableLayoutPanel tlp in panelFilters.Controls)
    {
        if(tlp != null)
        {
            tlp.SuspendLayout();
        }
    }
}

private void FilterForm_ResizeEnd(object sender, EventArgs e)
{
    foreach (TableLayoutPanel tlp in panelFilters.Controls)
    {
        if (tlp != null)
        {
            tlp.ResumeLayout();
        }
    }
}

Please let me know if there is a trick to make tablelayoutpanel to work faster...or if you know a better approach to lay down about hundred of controls nicely aligned.

Dumbo
  • 13,555
  • 54
  • 184
  • 288
  • 1
    Having fewer controls is going to be the ultimate solution to this problem. – LarsTech Jan 17 '12 at 20:29
  • That would be ideal...But there are moments you really need those controls! – Dumbo Jan 27 '12 at 14:13
  • There are ways of limiting the controls. Sometimes you can eliminate labels and just draw the text in the paint event. Maybe consider [this answer](http://stackoverflow.com/a/8930446/719186) since it sounds like it might be the same issue. BTW, you probably don't have to loop through the controls like you are, try just using `panelFilters.SuspendLayout();` and see what happens. – LarsTech Jan 27 '12 at 14:26
  • 2
    I'd love to see a screenshot and the user manual for this app. – Ritch Melton Apr 06 '12 at 03:30

2 Answers2

24

Use this code.

public class CoTableLayoutPanel : TableLayoutPanel
{
    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.CacheText, true);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= NativeMethods.WS_EX_COMPOSITED;
            return cp;
        }
    }

    public void BeginUpdate()
    {
        NativeMethods.SendMessage(this.Handle, NativeMethods.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
    }

    public void EndUpdate()
    {
        NativeMethods.SendMessage(this.Handle, NativeMethods.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
        Parent.Invalidate(true);
    }
}

public static class NativeMethods
{
    public static int WM_SETREDRAW = 0x000B; //uint WM_SETREDRAW
    public static int WS_EX_COMPOSITED = 0x02000000; 


    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); //UInt32 Msg
}
NET3
  • 1,520
  • 1
  • 16
  • 25
  • 4
    Great implementation. I had a tpl with 70 controls in it that would take 10 seconds to render. With this change it's instantaneous. – Jason Turan Oct 08 '13 at 15:57
  • 2
    Seems to help. The graphics drawing appears to occur all at once with this. – mbomb007 Jun 09 '16 at 20:48
  • @NET3 this is the best answer of all the answers out there for flicker, is there anything more we can do to improve performance, like increase memory allowance or using 64bit when available? – sam Feb 06 '18 at 01:42
  • How should we make this in a VS project? A Custom Control item, a Usercontrol, an Inherited Usercontrol or just make a new Class and paster this code in? – RBarryYoung Feb 15 '18 at 17:50
  • 1
    Dear @RBarryYoung Just add this class to your VS project and then you can derive from it to create a new custom user control as your desire or just use it on your form class directly. – NET3 Feb 17 '18 at 14:31
  • For my form with lots of controls, this code makes it APPEAR to work faster (due to the compositing, which made all the widgets appear at once), but the overall form load time was pretty much the same. The benefit from double buffering and using WM_SETREDRAW was also so small as to be indiscernible from the noise. Also, you are better off adding compositing to the whole form, rather than to the individual TableLayoutPanels. However, I did get a BIG performance increase by running SuspendLayout on every control before changing properties on widgets, then running ResumeLayout(false). – philu Jun 02 '21 at 06:14
1

If you create a new class derived from TableLayoutPanel and set the ControlStyles such that DoubleBuffered is true, your performance will improve dramatically.

public class MyPanel :  TableLayoutPanel
{
    public MyPanel()
    {
        this.SetStyle(ControlStyles.DoubleBuffer, true);
    }

}
Jacob G
  • 3,645
  • 1
  • 20
  • 25