使用从面板派生的自定义控件固定在OnPaint循环中

时间:2013-11-21 22:36:00

标签: winforms c#-4.0 user-controls panel onpaint

我有一个自定义面板,可以显示纯色背景色,渐变背景色或图片。

我已经覆盖了BackgroundImage属性和OnPaint方法,如下所示:

protected override void OnPaint(PaintEventArgs pe){
    Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
    if (this.DrawStyle != DrawStyle.Picture){
        base.BackgroundImage = null;

            if (this.DrawStyle == DrawStyle.Solid){
                using (SolidBrush brush = new SolidBrush(this.PrimaryColor))
                    pe.Graphics.FillRectangle(brush, rc);
            }
            else if (this.DrawStyle == DrawStyle.Gradient){
                using (LinearGradientBrush brush = 
                       new LinearGradientBrush(
                           rc, this.PrimaryColor, this.SecondaryColor, this.Angle))
                pe.Graphics.FillRectangle(brush, rc);
            }
        }
    else if (this._BGImage != null)
        base.BackgroundImage = this._BGImage;
}

public override Image BackgroundImage{
    get { return this._BGImage; }
    set { this._BGImage = value; }
}

原因是控件必须足够灵活,以便在运行时更改背景类型(Solid,Gradient或Picture),因此控件会保留在设置的背景图像上并在必要时显示。

然而,我遇到了一个问题。

如果我没有设置背景图像,则没有问题。 OnPaint被调用大约5次然后就可以了。

然而,当我设置背景图像时,它似乎变得疯狂,一遍又一遍地反复调用OnPaint。

这显然与覆盖背景图像有关,这是一个问题,因为它是挂起的,面板上的任何内容都没有更新,直到我更改面板外观。

所以我想我的问题是为什么当我设置背景图片时它会卡在这个OnPaint循环中?

1 个答案:

答案 0 :(得分:2)

注释掉这个:

// base.BackgroundImage = this._BGImage;

它导致它以递归方式绘制自己。您永远不应该在绘图例程中设置属性。

此外,您没有通过覆盖BackgroundImage来完成任何事情,如果您覆盖该属性,那么它应该是您分配base.BackgroundImage值的唯一位置。考虑删除它。

我将您的代码重写为:

protected override void OnPaintBackground(PaintEventArgs e) {
  if (this.DrawStyle == DrawStyle.Picture) {
     base.OnPaintBackground(e);
  }
}

protected override void OnPaint(PaintEventArgs e) {
  Rectangle rc = this.ClientRectangle;
  if (this.DrawStyle == DrawStyle.Solid) {
    using (SolidBrush brush = new SolidBrush(this.PrimaryColor))
      e.Graphics.FillRectangle(brush, rc);
  } else if (this.DrawStyle == DrawStyle.Gradient) {
    using (LinearGradientBrush brush =
           new LinearGradientBrush(
               rc, this.PrimaryColor, this.SecondaryColor, this.Angle))
      e.Graphics.FillRectangle(brush, rc);
  }
  base.OnPaint(e);
}

请务必在面板的构造函数中添加this.DoubleBuffered = true;this.ResizeRedraw = true;,以避免不必要的闪烁。