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:
- When I try to run a form with the component on, I get an Argument Exception on
Application.Run(new Form());
. - 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);
}
}
}
}