是什么原因导致Double Buffering终止我的应用程序? [英] What could cause Double Buffering to kill my app?

查看:106
本文介绍了是什么原因导致Double Buffering终止我的应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用GDI +绘制到屏幕上的自定义(winforms)组件.

为了防止在重绘时闪烁,我决定启用双重缓冲,因此我在构造函数中添加了一行:

public ColourWheel()
{
    InitializeComponent();
    this.DoubleBuffered = true;
}

在此组件(ColourWheel)上可以正常工作.当我在其他两个(结构相似)组件的构造函数中添加同一行时,会出现一些奇怪的症状:

  1. 当我尝试运行带有该组件的表单时,在Application.Run(new Form());上收到了Argument异常.
  2. 如果我切换到设计模式,则会收到有关该组件的未处理异常与参数有关的错误消息.

我是否对其中一个或所有都启用双重缓冲似乎并不重要,它仍然可以在ColourWheel上使用,而对其他缓冲则不起作用.

为了记录,我还尝试了其他一些 double 解决方案

您不应该处置在Paint事件期间借给您的Graphics对象,而这正是您的using块所不正确的.

症状是,下次Paint事件触发时,您会返回相同的Graphics对象,但不再绑定到内存中的HDC,从而导致Graphics.GetHdc()失败,如所见在您的堆栈跟踪中.

  1. 它有可能超过单个Paint事件(并且双缓冲很可能是这种情况,但是如果设置了CS_OWNDC窗口样式,则也有可能使用单缓冲)./p>

  2. Paint事件可以有多个处理程序.

因此,事件处理程序不应在Graphics对象上调用Dispose或不允许使用using块进行调用.相反,.c框架会在Paint事件处理完成后适当地清理资源.

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;
}

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. When I try to run a form with the component on, I get an Argument Exception on Application.Run(new Form());.
  2. If I switch to design mode, I get an error about the component having an unhandled exception to do with a parameter.

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.

For the record, I've also tried a few other double buffering techniques.

What could be causing double buffering to work on one component, but not others?


EDIT: Here's the exception detail from the run-time symptom:

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 Settings\Tom Wright\My Documents\Visual Studio 2010\Projects\ColourPicker\TestForm\Program.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:


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);
               }
           }
        }
}

解决方案

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.

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. 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).

  2. There can be more than one handler for the Paint event.

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.

这篇关于是什么原因导致Double Buffering终止我的应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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