什么可能导致双缓冲杀死我的应用程序?
我有一些使用GDI +绘制到屏幕的自定义(winforms)组件。
为了防止重绘闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:
public ColourWheel() { InitializeComponent(); this.DoubleBuffered = true; }
哪个适用于此组件(ColourWheel)。 当我将同一行添加到我的另外两个(结构相似的)组件的构造函数中时,我会得到一些奇怪的症状:
- 当我尝试运行组件打开的表单时,我在
Application.Run(new Form());
上获得了一个Argument ExceptionApplication.Run(new Form());
。 - 如果我切换到设计模式,我得到一个错误,关于具有未处理的exception的组件与参数。
我是否对其中一个或全部进行双缓冲似乎并不重要,它仍然适用于ColourWheel,但不适用于其他人。
为了记录,我还尝试了一些其他双 缓冲技术。
什么可能导致双缓冲在一个组件上工作,而不是其他组件?
编辑:这是运行时症状的exception细节:
System.ArgumentException未处理Message = Parameter无效。 Source = System.Drawing StackTrace:System.Drawing.Graphics.GetHdc(),位于System.Windows.Forms.Control的System.Drawing.BufferedGraphics.Render()的System.Drawing.BufferedGraphics.RenderInternal(HandleRef refTargetDC,BufferedGraphics缓冲区)中。系统中System.Windows.Forms.UserControl.WndProc(Message&m)的System.Windows.Forms.ScrollableControl.WndProc(Message&m)处的System.Windows.Forms.Control.WndProc(Message&m)处的.WmPaint(Message&m) .Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&m)at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&m)at 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 reason,Int32 pvLoopData)at at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason,ApplicationContext context),位于TestForm.Program.Main()的System.Windows.Forms.Application.Run(Form mainForm)的System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,ApplicationContext context)中D:\ Documents and Settings \ Tom Wright \ My Documents \ Visual Studio 2010 \ Projects \ ColourPicker \ TestForm \ Program.cs:System.AppDomain.ExExcuteAssembly(RuntimeAssembly assembly,String [] args)的第18行,位于System.AppDomain.ExecuteAssembly (String assemblyFile,Evidence assemblySecurity,String [] args)在System.Threading.ExecutionContext.Run的System.Threading.ThreadHelper.ThreadStart_Context(Object state)中的Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()(ExecutionContext executionContext,ContextCallback callback) System.Threading.ThreadHelper.ThreadStart()InnerException上的System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态),对象状态,布尔值ignoreSyncCtx) :
编辑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()
失败,如堆栈跟踪中所示。
-
它有可能超过单个
Paint
事件(这很可能是双缓冲的情况,但如果设置了CS_OWNDC
窗口样式,也可以使用单缓冲)。 -
Paint
事件可以有多个处理程序。
因此,事件处理程序不应在Graphics
对象上调用Dispose
或允许using
块执行此操作。 相反,.NET框架会在Paint
事件处理完成后根据需要清理资源。
您应该在另一台计算机上测试它,看看它是否只是您的计算机。 在大多数情况下,这不应该是双缓冲的结果,但要检查你是否处理了你不应该在Paint事件中的任何元素,或者在代码中做任何事情,如果做了两次就会有问题。