9

我有一些使用 GDI+ 绘制到屏幕上的自定义(winforms)组件。

为了防止重绘时闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:

public ColourWheel()
{
    InitializeComponent();
    this.DoubleBuffered = true;
}

在这个组件(ColourWheel)上效果很好。当我将同一行添加到其他两个(结构相似的)组件中的任何一个的构造函数中时,我得到了一些奇怪的症状:

  1. 当我尝试在打开组件的情况下运行表单时,我得到一个 Argument Exception on Application.Run(new Form());
  2. 如果我切换到设计模式,我会收到一个错误,提示组件有一个与参数有关的未处理异常。

我是否在其中一个或全部上打开双缓冲似乎并不重要,它仍然适用于 ColourWheel,但不适用于其他。

作为记录,我还尝试了其他一些 缓冲技术。

什么可能导致双缓冲在一个组件上起作用,而在其他组件上不起作用?


编辑:这是运行时症状的异常详细信息:

System.ArgumentException 未处理 Message=Parameter 无效。Source=System.Drawing StackTrace:在 System.Drawing.Graphics.GetHdc() 在 System.Drawing.BufferedGraphics.RenderInternal(HandleRef refTargetDC, BufferedGraphics 缓冲区) 在 System.Drawing.BufferedGraphics.Render() 在 System.Windows.Forms.Control .WmPaint(Message& m) 在 System.Windows.Forms.Control.WndProc(Message& m) 在 System.Windows.Forms.ScrollableControl.WndProc(Message& m) 在 System.Windows.Forms.UserControl.WndProc(Message& m) 在 System .Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg,


编辑 2:来自导致问题的两个组件中的一个(更复杂的)的 OnPaint 处理程序:

private void ValueSlider_Paint(object sender, PaintEventArgs e)
{
       using (Graphics g = e.Graphics)
       {
           g.DrawImage(this.gradientImage, new Rectangle(0, 0, paintArea.Width, paintArea.Height));
           if (this.showmarker)
           {
               ColourHandler.HSV alt = ColourHandler.RGBtoHSV(new ColourHandler.RGB(this.SelectedColour.R, this.SelectedColour.G, this.SelectedColour.B));
               alt.Saturation = 0;
               alt.value = 255 - alt.value;
               using (Pen pen = new Pen(ColourHandler.HSVtoColour(alt)))
               {
                   pen.Width = (float)MARKERWIDTH;
                   g.DrawRectangle(pen, 0 - pen.Width, this.brightnessPoint.Y - MARKERWIDTH, this.paintArea.Width + (pen.Width * 2), MARKERWIDTH * 2);
               }
           }
        }
}
4

2 回答 2

12

你不应该在活动Graphics期间处理借给你的物品Paint,这就是你的using块不正确的做法。

症状是下次Paint事件触发时,您会Graphics返回相同的对象,但它不再绑定到 in-memory HDC,导致Graphics.GetHdc()失败,如您的堆栈跟踪所示。

  1. 它可能比单个Paint事件的寿命更长(这很可能是双缓冲的情况,尽管如果CS_OWNDC设置了窗口样式,单缓冲也可能出现这种情况)。

  2. 该事件可以有多个处理程序Paint

因此,事件处理程序不应调用Dispose对象Graphics或允许using块这样做。Paint相反,.NET 框架会在事件处理完成后适当地清理资源。

于 2012-02-04T14:36:30.293 回答
1

您应该在另一台机器上测试它,看看它是否只是您的计算机。在大多数情况下,这不应该是双缓冲的结果,但请检查您是否正在处理任何您不应该在 Paint 事件中出现的元素,或者是否在代码中执行任何如果执行两次就会出现问题的事情。

于 2012-02-03T20:15:20.073 回答