在我执行所有更新之前,我可以暂停重新绘制表单吗?

时间:2009-03-05 17:37:00

标签: .net winforms drawing transparency redraw

使用C#和.Net 2.0,我使用的形状不规则(TransparencyKey,FormBorderStyle = None等等)并希望允许“正常”的边框模式。

我将背面颜色从Lime改为默认颜色 我将FormBorderStyle更改为FixedSingle 我将TransparencyKey更改为Colour.None

不幸的是,这在屏幕上看起来完全混乱,图像向下跳了几个像素,一边是石灰绿色。

我认为这是由在每行代码后重绘的表单造成的,是否可以暂停绘制表单,直到我完成更改,然后只重绘表单一次?

5 个答案:

答案 0 :(得分:8)

新答案:在应用新窗口属性时覆盖WndProc并阻止WM_PAINT消息。

OLD answer:覆盖WndProc,并阻止WM_ERASEBKGND消息。

以下代码的说明:

当窗口的区域无效时,Windows会向控件发送一系列消息,从而生成一个新绘制的窗口小部件。本系列的早期信息是WM_ERASEBKGND。通常,响应此消息,控件将自身绘制为纯色。稍后,响应WM_PAINT消息(通常由我们在OnPaint事件中使用),实际绘图完成。如果这个绘图非常重要,那么在更新小部件之前会有一段延迟,你会得到恼人的闪烁。

再次查看您的代码,我显然正在解决另一个问题。试试这个新例子。如果未设置bAllowPaint标志,它将阻止表单/控件的绘制。

NEW 示例:

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

OLD 示例:

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

答案 1 :(得分:4)

尝试使用Form.DoubleBuffered属性。将其设置为“true”。

此外,如果您的表单有任何子控件,也可以将DoubleBuffered设置为true(以及子项的子项等)。

最后,在更改之前调用SuspendLayout,然后调用ResumeLayout。请记住,这只会影响子控件的放置。如果您正在进行任何自定义绘图,DoubleBuffered属性将为您提供更多优惠。

答案 2 :(得分:4)

您正在修改对表单具有相当大影响的属性。 TransparencyKey和FormBorderStyle需要更改窗口样式位。 Windows不允许更改这些样式位。 Windows Forms通过完全销毁窗口并从头开始重新创建窗口来实现它们。整洁的技巧,但这需要时间,每次你改变风格时,表格都会重新粉刷。导致你看到令人不快的视觉效果。

试试这个: 1.将“不透明度”设置为0,使表单变为不可见 2.改变BackColor,没问题 3.更改FormBorderStyle,重新创建窗口 4.更改TransparencyKey,重新创建窗口 5.将不透明度更改为1,窗口重新创建,然后可见

例如:

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

答案 3 :(得分:3)

如果一切都失败了,你可以通过阻止所有绘制消息到你的表单来尝试一些低级别的黑客攻击。

警告:我不推广使用此方法,但如果您真的想要,可以试试。它在过去帮助了我。

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

此代码依赖于以下支持代码:

public class Win32
{
  private Win32() { }

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

答案 4 :(得分:0)

将表单的所有“图像”一步发送到屏幕的方法是启用DoubleBuffer。

在构造函数中,您可以设置ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)