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

隐身守侯 提交于 2019-12-17 18:24:59

问题


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


回答1:


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);
        }
    }



回答2:


Try the Form.DoubleBuffered property. Set it to 'true'.

Also, if your form has any child controls, also set DoubleBuffered to true for those as well (and children's children, etc, down the line).

Lastly, call SuspendLayout before your changes and ResumeLayout afterwards. Keep in mind this only affects placement of child controls. If you are doing any custom drawing the DoubleBuffered property will give you more bang for the buck.




回答3:


You are modifying properties that have a rather large impact on a form. TransparencyKey and FormBorderStyle require changing the window style bits. Windows doesn't allow those style bits to be changed. Windows Forms implements them by completely destroying the window and re-creating it from scratch. Neat trick, but that takes time and the form will be repainted each time you change the style. Causing the unpleasant visual effect you see.

Try this: 1. Set Opacity to 0 so the form becomes invisible 2. Change BackColor, no problem 3. Change FormBorderStyle, window gets recreated 4. Change TransparencyKey, window gets recreated 5. Change Opacity to 1, window gets recreated, then visible

For example:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;



回答4:


If all that fails, you could try some lowlevel hacking by blocking all paint messages to your form.

WARNING: I am not promoting the use of this method, but you can try it if you really want to. It has helped me in the past.

Win32.LockWindowUpdate(this.Handle);
try
{
   //make your changes here
}
finally
{
  //release the lock
  Win32.LockWindowUpdate((IntPtr)0);
}

This code relies on the following supporting code:

public class Win32
{
  private Win32() { }

    /// <summary>
    /// Lock ore relase the wndow for updating.
    /// </summary>
    [DllImport("user32")]
    public static extern int LockWindowUpdate(HWND hwnd);
 }



回答5:


A way to send all the "image" of the form to the screen in one step is to enable DoubleBuffer.

In the Constructor you can set the ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)


来源:https://stackoverflow.com/questions/615781/can-i-suspend-redrawing-of-a-form-until-i-have-performed-all-updates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!