What could cause Double Buffering to kill my application?

I have several winforms components that draw on the screen using GDI +.

To prevent flickering when redrawing, I decided to enable double buffering, so I added a line to my constructor:

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

Which works great on this component (ColourWheel). When I add the same line to the constructor of any of the other two (similarly structured) components, I get some strange symptoms:

  • When I try to run a form with the component turned on, I get an Argument Exception on Application.Run(new Form()); .
  • If I switch to development mode, I get an error when a component that has an unhandled exception can use a parameter.

It doesn't seem to matter if I rotate double buffering on one or all of them, it still works on ColourWheel, but not on the others.

For the record, I also tried several other buffering .

What can cause double buffering to work with one component, but not with the other?


EDIT: Here is the detail of the exception to the symptom at runtime:

System.ArgumentException was unhandled Message = Parameter is not valid. Source = System.Drawing StackTrace: in System.Drawing.Graphics.GetHdc () in System.Drawing.BufferedGraphics.RenderInternal (HandleRef refTargetDC, BufferedGraphics buffer) in System.Drawing.BufferedGraphics.Render () in System.Windows.Forms.Control .WmPaint (Message & m) in System.Windows.Forms.Control.WndProc (Message & m) in System.Windows.Forms.ScrollableControl.WndProc (Message & m) in System.Windows.Forms.UserControl.WndProc (Message & m) in System.Windows.Forms.Control.ControlNativeWindow.OnMessage (Message & m) in System.Windows.Forms.Control.ControlNativeWindow.WndProc (Message & m) in System.Windows.Forms.NativeWindow.DebuggableCallback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) in System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW (MSG & msg) in System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManagerMessagerManager IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) in System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (Int32 reason, ApplicationContext context) in System.Windows.Forms.Application.ThreadContext.RunMessageLoop (Int32 reason, Windows.Forms.Application.Run (Form mainForm) in TestForm.Program.Main () in D: \ Documents and Settings \ Tom Wright \ My Documents \ Visual Studio 2010 \ Projects \ ColorPicker \ TestForm \ Program.cs: line 18 in System.AppDomain._nExecuteAssembly (assembly RuntimeAssembly, String [] args) in System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args) in Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssThread.Thread. System.readun.read .ThreadStart_Context (object state) in System.Threading.ExecutionContext.Run (ExecutionCo ntext executeContext, ContextCallback callback, object state, boolean ignoreSyncCtx) in System.Threading.ExecutionContext.Run (ExecutionContext executeContext, ContextCallback callback, object state) in System.Threading.ThreadHelper.ThreadStart () InnerException:


EDIT 2: OnPaint handler from one (more complex) of two components 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); } } } } 
+6
source share
2 answers

You should not place the Graphics object provided to you during the Paint event, and that your using block does not execute correctly.

The symptom is that the next time the Paint event you get the same Graphics object, but it is no longer tied to the HDC memory, causing Graphics.GetHdc() crash, as seen in your stack trace.

  • It is possible that he is experiencing a single Paint event (and this is most likely a double-buffered case, although this is also possible with single-buffering if the CS_OWNDC window style is set).

  • There can be more than one handler for a Paint event.

Thus, event handlers should not call Dispose on Graphics objects or allow the using block to do this. Instead, the .NET environment cleans resources as needed after the completion of the Paint event processing.

+8
source

You must check this on another machine to make sure that it is only your computer or not. For the most part, this should not happen as a result of double buffering, but check if you are removing any elements that should not be in the Paint event, or doing something in the code that will have problems if this is done twice.

+1
source

Source: https://habr.com/ru/post/907608/


All Articles