什么可能导致双缓冲区杀死我的应用程序
本文关键字:我的 应用程序 双缓冲区 什么 | 更新日期: 2023-09-27 18:22:20
我有一些自定义(winforms)组件,它们使用GDI+绘制到屏幕上。
为了防止重新绘制时出现闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:
public ColourWheel()
{
InitializeComponent();
this.DoubleBuffered = true;
}
这在该组件(彩色轮)上运行良好。当我在其他两个(结构相似)组件的构造函数中添加同一行时,我会出现几个奇怪的症状:
- 当我尝试在组件打开的情况下运行窗体时,
Application.Run(new Form());
上会出现Argument Exception - 如果我切换到设计模式,我会得到一个关于组件有一个与参数有关的未处理异常的错误
我是对其中一个还是全部启用双缓冲似乎并不重要,它仍然适用于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()
失败,如堆栈跟踪中所示。
-
它可能比单个
Paint
事件更持久(双缓冲的情况很可能是这样,尽管如果设置了CS_OWNDC
窗口样式,单缓冲也可能)。 -
Paint
事件可以有多个处理程序。
因此,事件处理程序不应该在Graphics
对象上调用Dispose
,也不应该允许using
块这样做。相反,.NET框架会在Paint
事件处理完成后酌情清理资源。
您应该在另一台机器上测试它,看看它是否只是您的计算机。在大多数情况下,这不应该是双重缓冲的结果,但请检查是否正在处理任何不应该出现在Paint事件中的元素,或者是否在代码中执行任何如果执行两次就会出现问题的操作。