Can I suspend redrawing of a form until I have performed all updates?

G-. picture G-. · Mar 5, 2009 · Viewed 12.4k times · Source

Using C# and .Net 2.0, I'm using an irregularly shaped form (TransparencyKey, FormBorderStyle = None, etc...) and want to allow "normal" bordered mode.

I change the back colour to default from Lime I change FormBorderStyle to FixedSingle I change the TransparencyKey to Colour.None

Unfortuanately this looks a complete mess on screen with the image jumping a few pixels down and to the side and Lime green form.

I think this is caused by the form being redrawn after each line of code, is it possible to suspend drawing the form until I have made my changes and then just redraw the form once?

G

Answer

overslacked picture overslacked · Mar 5, 2009

NEW answer: Override the WndProc and block the WM_PAINT message while you apply the new Window properties.

OLD answer: Override the WndProc, and block the WM_ERASEBKGND message.

Explanation of what the code below does:

When a window's region is invalidated, Windows sends a series of messages to the control that result in a freshly-painted widget. An early message in this series is WM_ERASEBKGND. Normally, in response to this message, the control paints itself a solid color. Later, in response to the WM_PAINT message (which is usually consumed by us in the OnPaint event) the actual drawing is done. If this drawing is non-trivial there will be a delay before the widget is updated and you'll get an annoying flicker.

Looking at your code again I was clearly solving a different problem. Try this new example. It will block the painting of the form/control if the bAllowPaint flag is unset.

The NEW example:

    private const int WM_PAINT = 0x000F;

    protected override void WndProc(ref Message m)
    {
        if ((m.Msg != WM_PAINT) ||
            (bAllowPaint && m.Msg == WM_PAINT))
        {
            base.WndProc(ref m);
        }
    }

The OLD example:

    private const int WM_ERASEBKGND = 0x0014;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg != WM_ERASEBKGND) // ignore WM_ERASEBKGND
        {
            base.WndProc(ref m);
        }
    }