什么可能导致双缓冲杀死我的应用程序?

时间:2012-02-03 19:14:28

标签: c# components gdi+ double-buffering

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

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

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

这个组件(ColourWheel)可以正常工作。当我将相同的行添加到我的另外两个(结构相似的)组件的构造函数中时,我会遇到几个奇怪的症状:

  1. 当我尝试运行组件打开的表单时,我在Application.Run(new Form());上得到了一个参数异常。
  2. 如果我切换到设计模式,我会收到有关参数的未处理异常的组件的错误。
  3. 我是否对其中一个或全部进行双缓冲似乎并不重要,它仍然适用于ColourWheel,但不适用于其他人。

    为了记录,我还尝试了其他一些double buffering技术。

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


    编辑:以下是运行时症状的异常详情:

      

    System.ArgumentException未处理Message =参数未处理   有效。 Source = System.Drawing StackTrace:          在System.Drawing.Graphics.GetHdc()          在System.Drawing.BufferedGraphics.RenderInternal(HandleRef refTargetDC,BufferedGraphics buffer)          在System.Drawing.BufferedGraphics.Render()          在System.Windows.Forms.Control.WmPaint(消息& m)          在System.Windows.Forms.Control.WndProc(消息& m)          在System.Windows.Forms.ScrollableControl.WndProc(消息& m)          在System.Windows.Forms.UserControl.WndProc(消息& 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,IntPtr wparam,IntPtr lparam)          在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)          在System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr)   dwComponentID,Int32原因,Int32 pvLoopData)          在System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32)   原因,ApplicationContext上下文)          在System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32)   原因,ApplicationContext上下文)          在System.Windows.Forms.Application.Run(Form mainForm)          在D:\ Documents and Settings \ Tom Wright \ My Documents \ Visual Studio中的TestForm.Program.Main()   2010 \ Projects \ ColourPicker \ TestForm \ Program.cs:第18行          在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)          在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)          在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()          在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)          at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean   ignoreSyncCtx)          在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)          在System.Threading.ThreadHelper.ThreadStart()InnerException:


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

2 个答案:

答案 0 :(得分:10)

您不应该在Graphics事件期间处置借给您的Paint对象,这就是您的using阻止不正确的行为。

症状是,下次Paint事件触发时,您将获得相同的Graphics对象,但它不再绑定到内存中HDC,导致{ {1}}在堆栈跟踪中看到失败。

  1. 它有可能超过单个Graphics.GetHdc()事件(这很可能是双缓冲的情况,尽管如果Paint窗口样式是单缓冲也可能设定)。

  2. CS_OWNDC事件可以有多个处理程序。

  3. 因此,事件处理程序不应在Paint对象上调用Dispose或允许Graphics块执行此操作。相反,在using事件处理完成后,.NET框架会根据需要清理资源。

答案 1 :(得分:1)

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