0

I've a WinForm application (double buffer enabled) with a TableLayoutPanel containing some DataGridView, some ActiveX control (from NI TestStand) and some labels. I added some code to Form CellPaint event to draw borders where I need.

One label is showing, via Systems.Windows.Forms.Timer, the actual DateTime, incrementing each second. At each update the form is flickering. If I comment the code in CellPaint event, flickering stops.

Adding:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

solves the flickering issue with CellPaint code enabled, but only if I don't resize the form. After resize, flickering starts and never stops.

I tried several proposal found here on SO, with no luck, suspending layout as suggester here, using reflection to enable double buffering on each control.

How can I avoid the flickering also after the resize?

EDIT: Here below the code related to Cellpaint event:

private void LayoutMainWindow_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
    SuspendLayout();
    if (e.Row == 0 && e.Column > 0)
    {
        DrawBottomBorder(e, 1);
    }
    if (e.Row == 1 && e.Column != 0)
    {
        DrawBottomBorder(e, 2);
    }
    if (e.Row <= 8 && e.Column == 0)
    {
        DrawRightBorder(e, 2);
    }
    if (e.Row == 2 && e.Column == 0)
    {
        DrawBottomBorder(e, 2);
    }
    if ((e.Row >= 2 && e.Row <= 7) && e.Column == 2)
    {
        DrawRightBorder(e, 2);
    }
    if (e.Row == 7 && e.Column <= 4)
    {
        DrawBottomBorder(e, 2);
    }
    if (e.Row >= 8 && e.Row <= 9)
    {
        DrawBottomBorder(e, 2);
    }
    if (e.Row == 9 && e.Column == 0)
    {
        DrawRightBorder(e, 2);
    }
    ResumeLayout();
}

private static void DrawRightBorder(TableLayoutCellPaintEventArgs e, float width)
{
    Rectangle r = e.CellBounds;
    using (Pen pen = new Pen(Color.Gray, width))
    {
        e.Graphics.DrawLine(pen, r.X + r.Width, r.Y, r.X + r.Width, r.Y + r.Height);
    }
}

private static void DrawBottomBorder(TableLayoutCellPaintEventArgs e, float width)
{
    Rectangle r = e.CellBounds;
    using (Pen pen = new Pen(Color.Gray, width))
    {
        e.Graphics.DrawLine(pen, r.X, r.Y + r.Height, r.X + r.Width, r.Y + r.Height);
    }
}
grandangelo
  • 172
  • 3
  • 10
  • 1
    Where is code related to flickering? – Renatas M. Aug 02 '18 at 08:18
  • You can't expect winforms to run this performant. It's not made for it. – slow Aug 02 '18 at 08:18
  • @sLw: _You can't expect winforms to run this performant._ Huh? What do you mean?? One screen update per second is too much? Nonsense!! – TaW Aug 02 '18 at 08:38
  • TableLayoutPanel is not double-buffered, so that easily explains the flicker from CellPainting. Do dig a bit deeper, if it flickers continuously then you have a nasty problem with the paint event firing over and over again. You are now hiding this problem, not good. Should be visible from Task Manager, Processes tab with your program burning 100% core. Happens when a paint event handler causes a paint again. Not so easy to see why from the snippet, that *might* be caused by Suspend/ResumeLayout(). They certainly don't belong in a paint event handler. – Hans Passant Aug 02 '18 at 09:11
  • @HansPassant CellPaint event is fired at start up, at each resize, and every one second, when label containing DateTime is updated. I checked and I'm not hogging the CPU. Nevertheless, I removed Suspend/Resume layout as per your suggestion. – grandangelo Aug 02 '18 at 09:22

1 Answers1

2

Thanks to TaW suggestion, as far as CellPaint is related to a TableLayout containing all the controls inside the Form:

private static void SetDoubleBuffered(Control c)
{
    if (System.Windows.Forms.SystemInformation.TerminalServerSession)
        return;
    System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.Instance);
    aProp.SetValue(c, true, null);
}

And then:

SetDoubleBuffered(LayoutMainWindow);

It fixes my issue. Thank you very much guys.

grandangelo
  • 172
  • 3
  • 10
  • This also worked for me with a big datagridview. I was adding the property to the panel containing the DGV but instead add the property to the DGV and flicker ended. – Tanner Ornelas Nov 06 '18 at 00:33