The TableLayoutPanel that comes with .NET 2.0 is handy for doing simple HTML style layouts without the hassle of having to embed a browser control in your form and write the HTML. The control is designed to be a lightweight container (not as powerful as the DataGridView, but more flexible in it's approach) and you can embed any control you like in it.
The main problem however is that the control flickers incredibly badly when it gets resized.
For windows forms applications the way to remove flickering is to enable double buffering. For a form you can just set the DoubleBuffered property to true, and while this will reduce flicker when you resize the form itself, the TableLayoutPanels on the form still flicker as they resize.
So to fix this you just need to turn on double buffering for the control. Unfortunately, the control doesn't feature a "DoubleBuffered" property.
You could try setting the ControlStyles for the control as well, however the SetStyle method is not exposed by the control.
So that means we'll need to use subclassing to set the double buffering flags. The following C# code shows you a simple double buffered TableLayoutPanel :
using System.ComponentModel;
using System.Windows.Forms;
namespace MyNameSpace
{
/// <summary>
/// Double Buffered layout panel - removes flicker during resize operations.
/// </summary>
public partial class DBLayoutPanel : TableLayoutPanel
{
public DBLayoutPanel()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint, true);
}
public DBLayoutPanel(IContainer container)
{
container.Add(this);
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint, true);
}
}
}
Create the class as shown, rebuild your code and the toolbox should now show you that a DBLayoutPanel control is available for your UI pleasure.
Oh, if you happen to have already built forms using the standard TableLayoutPanel you won't need to delete them and start again. Just go into the *.Designer.cs code-beside files and change the TableLayoutPanel references to DBLayoutPanel ones (watch your namespaces!). Rebuild your application and everything should run as it did before, this time without the flickering.
Thanks a lot, really good tip. ALTHOUGH I'm getting compiler errors for the "InitializeComponent();" lines. Any clues? Cheers...
ReplyDeletebleepy
That's a bit unusual. Without seeing the compiler error itself, I'd hazard a guess and say that you've got a missing reference or you're missing a using statement at the top of the code.
ReplyDeleteThis does not solve the problem. The fickering is reduced but it still exists.
ReplyDeleteWhat you may be seeing is flickering associated with other controls and you may also be coming up against the limitations of WinForms apps in general. I don't know that you'll get much improvement on what you see unless you move to WPF.
ReplyDeleteThe way WinForms apps are painted on the screen is not ideal and under any sort of CPU load you will likely see some flicker (though not much) and occasionally even some graphics artifacts.
WPF apps won't exhibit this behaviour as the drawing to the screen is handled by the graphics cards and the DirectX framework. In WinForms we're not so lucky and have to make do with what we have.
There is another solution:
ReplyDeletepublic partial class DBLayoutPanel : TableLayoutPanel {
public DBLayoutPanel()
{
this.DoubleBuffered = true;
}
}
This will avoid flickering at all.
Thanks for the tip with the DoubleBuffering.
ReplyDeleteI wondered why painting a table with some labels should flicker.
PS: Since .NET 2.0 you can set the DoubleBuffering value directly, like this:
public MyLayoutPanel : TableLayoutPanel{
public MyLayoutPanel( ){
this.DoubleBuffered = true;
}
}
This was cool. I personally do not know how but this tip fixed my problem. Thank You,
ReplyDeleteAshish Raje
Thank you very much!
ReplyDeleteA nice trick. Thank you.
ReplyDeleteWorked like a charm. Thanks for post.
ReplyDeleteMagnificent. Thanks dude.
ReplyDeleteFor anyone listening out there...
ReplyDeleteI did all this and it reduced the flicker a great deal when the form loaded - but the flicker still existed when I added any new controls (labels) or if there were a lot of rows (>20)...
My solution: Make sure the CellBorderStyle is set to None. If you want lines, use the borders on the controls themselves. That did the trick for me.
I too had the same problem and Richard's solution worked perfectly well for me. Thank you so much!
ReplyDeleteIf you get compiler errors about InitializeComponent() missing, you have to add a new item from templates "Windows Forms/Custom Control", and not "class" or whatever.
ReplyDeleteThanks a lot to all. I have a 100% flicker-free tablelayoutpanel in Winforms.
ReplyDeleteBrilliant. Solved our bad flickering issue. Thanks
ReplyDeleteI had to do the same trick for containing and nested Panels, too; but it helped a great deal. Thanks! Matthias
ReplyDeleteThanks a Zillion..:) was having a difficult time since it is not the same if one is using Panel and the instructions were for Panel Class.
ReplyDeleteThank you! I've been looking for a way to solve this for ages.
ReplyDeleteThanks a lot! finally got fixed
ReplyDeleteYou have won free beer from me for life - I was almost on the verge of topping myself over this problem (having designed a program for 8 months night and day solid, I came up against a 'flicker' wall which I thought was insurmountable). Well done and thanks again - brilliant solution
ReplyDeleteray_chapman48@hotmail.com
This made my day! I had layers of controls in my form (panels, TableLayoutPanels, labels) and had no clue what was causing the flickering. I gave your solution a try because it was so easy and neat. Bingo! It worked like a charm! Thank you so much for a beautiful solution to a frustrating problem.
ReplyDeleteThanks a lot broseph. Simple, clear, and easy solution.
ReplyDeleteIf anyone is here simply trying to speed up the population of a TLP from a multidimensional array or datatable you can simply:
ReplyDeletetlp.SuspendLayout();
//Do your population;
tlp.ResumeLayout();
This doesn't buffer the table at all until it is completely populated. It speeds it up drastically. This is only good, however, when you're adding more than one element at a time.
Wonderful, thank you very much...
ReplyDeleteThank you, thank you a lot sir
ReplyDelete