What could cause Double Buffering to kill my app?(什么可能导致双缓冲杀死我的应用程序?)
问题描述
我有一些使用 GDI+ 在屏幕上绘制的自定义(winforms)组件.
I have a few custom (winforms) components that draw to the screen using GDI+.
为了防止重绘时闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:
To prevent flickering on repaint, I decided to enable double buffering, so I added a line to my constructor:
public ColourWheel()
{
InitializeComponent();
this.DoubleBuffered = true;
}
在这个组件(ColourWheel)上效果很好.当我将同一行添加到其他两个(结构相似)组件中的任何一个的构造函数中时,我得到了一些奇怪的症状:
Which works fine on this component (ColourWheel). When I add the same line to the constructor of either of my other two (similarly structured) components, I get a couple of strange symptoms:
- 当我尝试在打开组件的情况下运行表单时,我在
Application.Run(new Form());
上收到参数异常. - 如果我切换到设计模式,我会收到一个错误,提示组件有一个与参数有关的未处理异常.
我是否在其中一个或全部上打开双缓冲似乎并不重要,它仍然适用于 ColourWheel,但不适用于其他.
It doesn't seem to matter whether I turn double buffering on one or all of them, it still works on the ColourWheel, but not the others.
为了记录,我还尝试了其他一些 double 缓冲技术.
什么可能导致双缓冲在一个组件上起作用,而在其他组件上不起作用?
What could be causing double buffering to work on one component, but not others?
以下是运行时症状的异常详细信息:
Here's the exception detail from the run-time symptom:
System.ArgumentException 未处理 Message=Parameter is not有效的.源 = 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.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精)在 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(窗体 mainForm)在 D:Documents and SettingsTom WrightMy DocumentsVisual Studio 中的 TestForm.Program.Main()2010ProjectsColourPickerTestFormProgram.cs:第 18 行在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数)在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args)在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态)在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback 回调, 对象状态, Boolean忽略SyncCtx)在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态)在 System.Threading.ThreadHelper.ThreadStart() InnerException:
System.ArgumentException was unhandled Message=Parameter is not valid. Source=System.Drawing StackTrace: at System.Drawing.Graphics.GetHdc() at System.Drawing.BufferedGraphics.RenderInternal(HandleRef refTargetDC, BufferedGraphics buffer) at System.Drawing.BufferedGraphics.Render() at System.Windows.Forms.Control.WmPaint(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.UserControl.WndProc(Message& m) at System.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) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at TestForm.Program.Main() in D:Documents and SettingsTom WrightMy DocumentsVisual Studio 2010ProjectsColourPickerTestFormProgram.cs:line 18 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:
<小时>
编辑 2: 导致问题的两个组件之一(更复杂)的 OnPaint 处理程序:
EDIT 2: The OnPaint handler from one (the more complicated) of the two components that are causing problems:
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
块不正确的做法.
You aren't supposed to dispose the Graphics
object loaned to you during the Paint
event, and that's what your using
block improperly does.
症状是下一次 Paint
事件触发时,您会返回相同的 Graphics
对象,但它不再绑定到内存中的 HDC
,导致 Graphics.GetHdc()
失败,如堆栈跟踪所示.
The symptom is that the next time the Paint
event fires, you get the same Graphics
object back, but it is no longer bound to an in-memory HDC
, causing Graphics.GetHdc()
to fail as seen in your stack trace.
它可能比单个
Paint
事件的寿命更长(这很可能是双缓冲的情况,但如果CS_OWNDC
窗口样式已设置).
It's possible that it outlives a single
Paint
event (and this is very likely the case with double-buffering, although it's also possible with single-buffering if theCS_OWNDC
window style is set).
Paint
事件可以有多个处理程序.
There can be more than one handler for the Paint
event.
因此,事件处理程序不应在 Graphics
对象上调用 Dispose
或允许 using
块这样做.相反,.NET 框架会在 Paint
事件处理完成后适当地清理资源.
So, event handlers should not call Dispose
on the Graphics
objects or allow a using
block to do so. Instead, the .NET framework cleans up resources as appropriate after Paint
event handling is complete.
这篇关于什么可能导致双缓冲杀死我的应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:什么可能导致双缓冲杀死我的应用程序?
基础教程推荐
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- c# Math.Sqrt 实现 2022-01-01