views:

735

answers:

3

Hi, I'm writing a biorhythm app. To test it i have a form with a Button and a PictureBox. When I click on the button i do

myPictureBox.Image = GetBiorhythm2();

Which runs ok for the first time, but on the second click it causes the following exception:

System.ArgumentException: Parameter is not valid.
   at System.Drawing.Graphics.CheckErrorStatus
   at System.Drawing.Graphics.FillEllipse
   at Larifari.Biorhythm.Biorhythm.GetBiorhythm2 in c:\delo\Horoskop\Biorhythm.cs:line 157
   at Larifari.test.Button1Click in c:\delo\Horoskop\test.Designer.cs:line 169
   at System.Windows.Forms.Control.OnClick
   at System.Windows.Forms.Button.OnClick
   at System.Windows.Forms.Button.OnMouseUp
   at System.Windows.Forms.Control.WmMouseUp
   at System.Windows.Forms.Control.WndProc
   at System.Windows.Forms.ButtonBase.WndProc
   at System.Windows.Forms.Button.WndProc
   at ControlNativeWindow.OnMessage
   at ControlNativeWindow.WndProc
   at System.Windows.Forms.NativeWindow.DebuggableCallback
   at ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
   at ThreadContext.RunMessageLoopInner
   at ThreadContext.RunMessageLoop
   at System.Windows.Forms.Application.Run
   at Larifari.test.Main in c:\delo\Horoskop\test.cs:line 20

the cut-down function which causes the error is :

public static Image GetBiorhythm2() {
        Bitmap bmp = new Bitmap(600, 300);
        Image img = bmp;
        Graphics g = Graphics.FromImage(img);

        Brush brush = Brushes.Black;
        g.FillEllipse(brush, 3, 3, 2, 2); //Here the exception is thrown on the second call to the function

        brush.Dispose(); //If i comment this out, it works ok.

        return img;
 }

if I comment-out the brush disposal it works ok, but I am not happy with that and wish to find an alternative solution. Can you help me please ?

A: 

I don't think you need to call .Dispose on static brushes, only if you create new ones. Although, personally, I would use the using syntax.. ie:

using (Brush brush = new SolidBrush(...))
{
    g.FillEllipse(brush, 3, 3, 2, 2);
}

And you should probably do the same thing with the graphics object you create.

FryGuy
Yes, do not attempt to dispose of static brushes. I had a hell of a time tracking this one down once.
Ed Swangren
Wouldn't your code just set brush as a reference to the static brush, and then dispose it after the using block?
Jon B
No, he is creating a new brush here.
Ed Swangren
I updated the code after the post, so he wasn't wrong.
FryGuy
+7  A: 

Bruhes.Black is a system resource, and is not intended for you to dispose. The runtime manages the brushes in the Brushes class, the Pens, and other such objects. It creates and disposes those objects as required, keeping frequently-used items alive so that it doesn't have to continually create and destroy them.

The documentation for the Brushes class says:

The Brushes class contains static read-only properties that return a Brush object of the color indicated by the property name. You typically do not have to explicitly dispose of the brush returned by a property in this class, unless it is used to construct a new brush.

In short, do not call Dispose on the system-supplied objects.

Jim Mischel
More accurately, do not call Dispose on Static objects.
Adam N
+3  A: 

It looks like you're trying to dispose of a static, which causes some problems next time it's used:

    Brush brush = Brushes.Black;
    g.FillEllipse(brush, 3, 3, 2, 2); //Here the exception is thrown on the second call to the function

    brush.Dispose(); //If i comment this out, it works ok.

When you set brush = Brushes.Black, you're actually setting brush as a reference (or pointer) to the static Brushes.Black. By disposing it, you're effectively writing:

    Brushes.Black.dispose();

When you come back around to use the black brush again, the runtime says you can't because it's already been disposed of, and isn't a valid argument to g.FillEllipse()

A better way to write this might be just simply:

    g.FillEllipse(Brushes.Black, 3, 3, 2, 2);

Or, if you want to be really complex about it:

    Brush brush = Brushes.Black.Clone();
    g.FillEllipse( brush, 3, 3, 2, 2 );
    brush.Dispose();

Or if you don't care about things looking wrong, just comment out the brush.Dispose(); line in your original code.

Adam N
Thanks all, I get it now :) I wish they would make this a compile-time error...
Spikolynn