【问题标题】:Can I suspend redrawing of a form until I have performed all updates?我可以在执行所有更新之前暂停重绘表格吗?
【发布时间】:2010-10-11 13:48:11
【问题描述】:

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

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

不幸的是,这在屏幕上看起来完全是一团糟,图像向下和向侧面跳跃了几个像素,并形成了石灰绿色。

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

G

【问题讨论】:

标签: .net winforms drawing transparency redraw


【解决方案1】:

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

旧答案:覆盖 WndProc,并阻止 WM_ERASEBKGND 消息。

以下代码的作用说明:

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

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

新例子:

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

【讨论】:

  • 您能更详细地解释一下这是做什么的吗?我理解覆盖的概念,但是这段代码可以防止/做什么?
【解决方案2】:

如果一切都失败了,您可以尝试一些低级黑客攻击,方法是阻止所有绘制消息到您的表单。

警告:我不提倡使用这种方法,但如果你真的想尝试,你可以试试。它过去曾帮助过我。

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

【讨论】:

  • 根据msdn,这仅在拖放时使用:msdn.microsoft.com/en-us/library/windows/desktop/dd145034(v=vs.85).aspx跨度>
【解决方案3】:

您正在修改对表单有相当大影响的属性。 TransparencyKey 和 FormBorderStyle 需要更改窗口样式位。 Windows 不允许更改这些样式位。 Windows 窗体通过完全销毁窗口并从头开始重新创建它来实现它们。巧妙的技巧,但这需要时间,并且每次更改样式时都会重新绘制表单。造成你看到的不愉快的视觉效果。

试试这个: 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;

【讨论】:

【解决方案4】:

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

在构造函数中你可以设置 ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)

【讨论】:

    【解决方案5】:

    试试 Form.DoubleBuffered 属性。将其设置为“真”。

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

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

    【讨论】:

      猜你喜欢
      • 2012-03-26
      • 2008-11-07
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2021-05-01
      相关资源
      最近更新 更多