1

我正在构建这个问题并创建一个简单的 ImageButton 类,该类表示一个仅包含图像的按钮。我实施了(至少我相信我做到了)这个答案中的建议,但我仍然得到这个代码的异常:

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

当我尝试将此控件添加到设计器时,我得到

控件 ImageButton 在设计器中引发了未处理的异常并已被禁用。

例外:值不能为空。参数名称:图像

堆栈跟踪:ImageButton.cs:line48 中的 ImageButton.OnPaint(PaintEventArgs e)

第 48 行是这一行:

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

我意识到抛出此错误是因为BackgroundImage未设置为值,但我不确定如何在代码中执行此操作。在实际应用中,这个类永远不会添加到设计器中,而是以编程方式添加。我该如何解决这个异常?

4

5 回答 5

5
    this.BackgroundImage = base.BackgroundImage;

是的,当然,保证例外。您希望有人在构造函数运行之前设置了 BackgroundImage 属性。这是不可能的,构造函数在控件上的任何属性可以设置之前运行。

接下来出错的是 Paint 事件也将在设计器中引发。在您将控件放在表单上后立即发生这种情况。那是一个 Kaboom,用户和您的代码都没有给 BackgroundImage 属性赋值。所以只需修复方法:

protected override void OnPaint(PaintEventArgs e)
{
    if (BackgroundImage != null) e.Graphics.DrawImage(BackgroundImage, 0, 0);
}
于 2012-07-30T22:34:05.473 回答
2

要删除背景图像,只需编写:

this.BackgroundImage = null;
于 2014-08-27T14:00:50.433 回答
2

我不知道 C#,但我的猜测是在某处存储一个透明的 1x1px 图像并将其分配给 init。这样,就会有图像,但什么也看不到。

或者您可以尝试在第 48 行附近添加一些检查,如下所示:

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

也许添加这样的东西:

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

另一种方法是将DrawImage调用封装在一个try{}块中并捕获结果表达式。如果是空块,您应该能够安全地使用catch{}它。

于 2012-07-30T22:10:46.173 回答
0

如果没有设置图像时不绘制怎么办,在函数开头也调用base。

base.OnPaint(e);
于 2012-07-30T22:11:08.310 回答
0

您的实现中有很多冗余代码:试试这个修订版......

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();
            }
        }
    } 
于 2012-07-30T22:24:02.223 回答