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

本文关键字:我的 应用程序 双缓冲区 什么 | 更新日期: 2023-09-27 18:22:20

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

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

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

这在该组件(彩色轮)上运行良好。当我在其他两个(结构相似)组件的构造函数中添加同一行时,我会出现几个奇怪的症状:

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

我是对其中一个还是全部启用双缓冲似乎并不重要,它仍然适用于ColourWheel,但对其他部分无效。

为了记录在案,我还尝试了其他一些双重缓冲技术

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


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

System.ArgumentException未处理消息=参数不是有效的Source=System.Drawing StackTrace:位于System.Drawing.Graphics.GetHdc()位于System.Drawing.BufferedGraphics.RenderInternal(HandleRef-refTargetDC,BufferedGraphics缓冲区)位于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(消息&m)在System.Windows.Forms.NativeWindow.DebugableCallback(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(IntPtrdwComponentID,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:line 18位于System.AppDomain_nExecuteAssembly(RuntimeAssembly程序集,String[]参数)位于System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String[]args)位于Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()位于System.Threading.ThreadHelper.ThreadStart_Context(对象状态)在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态,布尔值ignoreSyncCtx)在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)在System.Threading.ThreadHelper.ThreadStart()内部异常:


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

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

您不应该在Paint事件期间处理借给您的Graphics对象,而using块就是这样做的。

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

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

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

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

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