什么可能导致双缓冲杀死我的应用程序? [英] What could cause Double Buffering to kill my app?

查看:16
本文介绍了什么可能导致双缓冲杀死我的应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用 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:

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

我是否在其中一个或全部上打开双缓冲似乎并不重要,它仍然适用于 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.

  1. 它可能比单个 Paint 事件的寿命更长(这很可能是双缓冲的情况,但如果 CS_OWNDC 窗口样式已设置).

  1. 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 the CS_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.

这篇关于什么可能导致双缓冲杀死我的应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆