我有一些使用GDI +绘制到屏幕的自定义(winforms)组件。
为了防止重绘时出现闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:
public ColourWheel()
{
InitializeComponent();
this.DoubleBuffered = true;
}
这个组件(ColourWheel)可以正常工作。当我将相同的行添加到我的另外两个(结构相似的)组件的构造函数中时,我会遇到几个奇怪的症状:
Application.Run(new Form());
上得到了一个参数异常。我是否对其中一个或全部进行双缓冲似乎并不重要,它仍然适用于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);
}
}
}
}
答案 0 :(得分:10)
您不应该在Graphics
事件期间处置借给您的Paint
对象,这就是您的using
阻止不正确的行为。
症状是,下次Paint
事件触发时,您将获得相同的Graphics
对象,但它不再绑定到内存中HDC
,导致{ {1}}在堆栈跟踪中看到失败。
它有可能超过单个Graphics.GetHdc()
事件(这很可能是双缓冲的情况,尽管如果Paint
窗口样式是单缓冲也可能设定)。
CS_OWNDC
事件可以有多个处理程序。
因此,事件处理程序不应在Paint
对象上调用Dispose
或允许Graphics
块执行此操作。相反,在using
事件处理完成后,.NET框架会根据需要清理资源。
答案 1 :(得分:1)
您应该在另一台计算机上测试它,看看它是否只是您的计算机。在大多数情况下,这不应该是双缓冲的结果,但要检查你是否处理了不应该在Paint事件中的任何元素,或者在代码中做任何事情,如果做了两次就会出现问题。