Ricardo Altamirano
Ricardo Altamirano

Reputation: 15208

How do I set the background image to None, or some other default value, in an image button?

I'm building off this question and creating a simple ImageButton class that represents a button containing only an image. I implemented (at least I believe I did) the suggestions in this answer, but I'm still getting an exception with this code:

public class ImageButton : Button
{
    // Overrides the property
    public override Image BackgroundImage
    {
        get { return base.BackgroundImage; }
        set
        {
            base.BackgroundImage = value;
            if (value != null) this.Size = value.Size;
        }
    }

    // Shadows the property (note the -new- keyword)
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new Size Size
    {
        get
        {
            return base.Size;
        }
        set
        {
            base.Size = value;
        }
    }

    public ImageButton()
    {
        this.BackgroundImage = base.BackgroundImage;
        this.BackgroundImageChanged += new EventHandler(ImageButton_BackgroundImageChanged);
    }

    void ImageButton_BackgroundImageChanged(object sender, EventArgs e)
    {
        this.Size = this.BackgroundImage.Size;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.DrawImage(BackgroundImage, 0, 0); // <-- Error occurs here
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        // Do nothing
    }
}

When I try to add this control to the designer, I get

The control ImageButton has thrown an unhandled exception in the designer and has been disabled.

Exception: Value cannot be null. Parameter name: image

Stack trace: ImageButton.OnPaint(PaintEventArgs e) in ImageButton.cs:line48

Line 48 is this line:

e.Graphics.DrawImage(BackgroundImage, 0, 0);

I realise that this error is thrown because BackgroundImage is not set to a value, but I'm unsure how to do so in the code. In the actual application, this class will never be added to the designer, but rather added programmatically. How can I fix this exception?

Upvotes: 2

Views: 15478

Answers (5)

djsony90
djsony90

Reputation: 47

to remove the background image just write:

this.BackgroundImage = null;

Upvotes: 3

Hans Passant
Hans Passant

Reputation: 942109

    this.BackgroundImage = base.BackgroundImage;

Yes, sure, guaranteed exception. You hope that somebody has set the BackgroundImage property before the constructor runs. That's not possible, the constructor runs before any property on the control can be set.

The next thing that goes wrong is that the Paint event will be raised in the designer as well. Which happens immediately after you drop the control on the form. That's a Kaboom, neither the user nor your code has given the BackgroundImage property a value yet. So just fix the method:

protected override void OnPaint(PaintEventArgs e)
{
    if (BackgroundImage != null) e.Graphics.DrawImage(BackgroundImage, 0, 0);
}

Upvotes: 6

Matthew Layton
Matthew Layton

Reputation: 42340

There is a lot of redundant code in your implementation: try this revised version...

public class ImageButton : Button
    {
        public ImageButton()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            //base.OnPaint(pevent); <-- NO LONGER NEEDED (WE DO NOT WANT THE SYSTEM TO PAINT THE BUTTON);
            if (this.BackgroundImage != null)
            {
                pevent.Graphics.DrawImage(this.BackgroundImage, 0, 0);
            }
            else
            {
                //Just fill in black (for example)
                pevent.Graphics.FillRectangle(new SolidBrush(Color.Black), this.ClientRectangle);
            }
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            pevent.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
        }

        public override Image BackgroundImage
        {
            get
            {
                return base.BackgroundImage;
            }
            set
            {
                base.BackgroundImage = value;
                this.Size = base.BackgroundImage.Size;
                this.Refresh();
            }
        }
    } 

Upvotes: 0

Nicolas Stamm
Nicolas Stamm

Reputation: 123

I don't know C#, but my guess for this would be to have a transparent 1x1px image stored somewhere and assign that on init. That way, there'd be an image but nothing will be seen.

Or you could try adding some check around line 48, like this:

if(BackgroundImage!=null){
    e.Graphics.DrawImage(BackGroundImage,0,0);
}

Maybe add something like this:

else{ //No background image
    //Draw some dummy/placeholder
}

Yet another method would be to encapsulate the DrawImage call within a try{} block and catch the resulting expression. You should be able to safely use an empty catch{}block if it's that one.

Upvotes: 2

Orn Kristjansson
Orn Kristjansson

Reputation: 3485

What if you don't draw when there is no image set, also call base in the beginning of the function.

base.OnPaint(e);

Upvotes: 0

Related Questions