2014-03-25 242 views
1

我發現了一些自定義groupbox的代碼,繪製圓角,漸變背景和陰影。我認爲它看起來不錯,所以我調整它與標籤控件一樣。自定義控件 - 第一次繪製好,第二次不會

奇怪的是,當我將這些控件中的一個放到窗體設計器上時,默認屬性被設置,並且它畫得很好 - 我在窗體上放置了多個副本,並且它們都很好。

但是,當我嘗試在運行時添加幾個控件時,實際上只能正確繪製第一個版本。其他人最終只是空白的白色盒子。

我真的不知道該怎麼做。

代碼標籤如下: -

public class LabelEx : Label 
{ 
    private System.Drawing.Color _BorderColor = Color.FromArgb(141, 178, 227); 
    private float _BorderWidth = 1; 
    private System.Drawing.Color _BackgroundColor = Color.White; 
    private System.Drawing.Color _BackgroundColorGradient = Color.FromArgb(227, 235, 246); 
    private ControlGradientMode _BackgroundGradientMode = ControlGradientMode.Vertical; 

    private int _CornerRadius = 5; 
    private RoundedControlCorners _Corners = RoundedControlCorners.All; 
    private int _DropShadowThickness = 3; 
    private bool _DropShadowVisible = true; 
    private System.Drawing.Color _ShadowColor = Color.FromArgb(50, Color.Black); 

    private ControlStyles _LabelStyle = ControlStyles.Extended; 

    public enum ControlStyles 
    { 
     Standard, 
     Extended 
    } 

    public LabelEx() 
    { 
     //InitializeComponent(); 
    } 

    /// <summary>Gets or sets the radius of the corners of the control.</summary> 
    //[Category("Appearance"), Description("This feature will round the corners of the control.")] 
    public int CornerRadius 
    { 
     get { return _CornerRadius; } 
     set 
     { 
      if (value > 35) 
      { 
       _CornerRadius = 35; 
      } 
      else 
      { 
       if (value < 1) 
       { 
        _CornerRadius = 1; 
       } 
       else 
       { 
        _CornerRadius = value; 
       } 
      } 
      Invalidate(); 
     } 
    } 
    /// <summary>Turns on or off the control shadowing.</summary> 
    //[Category("Appearance"), Description("This feature will turn on control shadowing.")] 
    public bool DropShadowVisible 
    { 
     get { return _DropShadowVisible; } 
     set 
     { 
      _DropShadowVisible = value; 
      Invalidate(); 
     } 
    } 
    /// <summary>Gets or sets the color of the control's border.</summary> 
    //[Category("Appearance"), Description("This feature will allow you to change the color of the control's border.")] 
    public System.Drawing.Color BorderColor 
    { 
     get { return _BorderColor; } 
     set 
     { 
      _BorderColor = value; 
      Invalidate(); 
     } 
    } 
    /// <summary>Gets or Sets the control's border size.</summary> 
    //[Category("Appearance"), Description("This feature will allow you to set the control's border size.")] 
    public float BorderWidth 
    { 
     get { return _BorderWidth; } 
     set 
     { 
      if (value > 10) 
      { 
       _BorderWidth = 10; 
      } 
      else 
      { 
       if (value < 1) 
       { 
        _BorderWidth = 1; 
       } 
       else 
       { 
        _BorderWidth = value; 

       } 
      } 

      Invalidate(); 
     } 
    } 
    /// <summary>Gets or sets the size of the shadow border thickness.</summary> 
    // [Category("Appearance"), Description("This feature will change the size of the shadow border.")] 
    public int DropShadowThickness 
    { 
     get { return _DropShadowThickness; } 
     set 
     { 
      if (value > 10) 
      { 
       _DropShadowThickness = 10; 
      } 
      else 
      { 
       if (value < 1) 
       { 
        _DropShadowThickness = 1; 
       } 
       else 
       { 
        _DropShadowThickness = value; 
       } 
      } 
      Invalidate(); 
     } 
    } 
    /// <summary>Gets or sets the background color to use. This color can also be used in combination with BackgroundColorGradient for a gradient paint.</summary> 
    // [Category("Appearance"), Description("This feature will change the group control color. This color can also be used in combination with BackgroundColorGradient for a gradient paint.")] 
    public System.Drawing.Color BackgroundColor 
    { 
     get { return _BackgroundColor; } 
     set 
     { 
      _BackgroundColor = value; 
      Invalidate(); 
     } 
    } 
    /// <summary>Specifies the second color when using the gradient mode.</summary> 
    // [Category("Appearance"), Description("This feature can be used in combination with BackgroundColor to create a gradient background.")] 
    public System.Drawing.Color BackgroundColorGradient 
    { 
     get { return _BackgroundColorGradient; } 
     set 
     { 
      _BackgroundColorGradient = value; 
      Invalidate(); 
     } 
    } 

    /// <summary>This property secifies the type of gradient to use when painting the background.</summary> 
    // [Category("Appearance"), Description("This feature turns on background gradient painting.")] 
    public ControlGradientMode BackgroundGradientMode 
    { 
     get { return _BackgroundGradientMode; } 
     set 
     { 
      _BackgroundGradientMode = value; 
      Invalidate(); 
     } 
    } 

    /// <summary>Specifies which corners to apply rounding for</summary> 
    public RoundedControlCorners Corners 
    { 
     get { return _Corners; } 
     set 
     { 
      _Corners = value; 
      Invalidate(); 
     } 
    } 

    /// <summary>Gets or sets the Style for the GroupBox. Standard duplicates the stock groupbox. Extended allows the customization ability</summary> 
    // [Category("Appearance"), Description("Gets or sets the Style for the GroupBox. Standard duplicates the stock groupbox. Extended allows the customization ability")] 
    // [DefaultValue(ControlStyles.Extended)] 
    public ControlStyles LabelStyle 
    { 
     get { return _LabelStyle; } 
     set 
     { 
      _LabelStyle = value; 
      Invalidate(); 
     } 
    } 

    /// <summary> 
    /// Function to paint the label as per what we want. 
    /// </summary> 
    /// <param name="e"></param> 
    protected override void OnPaint(PaintEventArgs e) 
    { 
     //Just use a normal label if the "standard" is set. 
     if (_LabelStyle == ControlStyles.Standard) 
     { 
      base.OnPaint(e); 
      return; 
     } 

     //we must set the smoothing mode to anti alias or high quality(They are the same) in order to get the 
     //nice rounded corders on our control 

     e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; 

     //first lets set the rectangles we will be drawing in. If the drop shadow is visible then we need to 
     //reduce the size of the main rectangle and create a second one that is offset by the shadow thickness. 
     Rectangle shadowRec = default(Rectangle); 
     Rectangle frameRec = default(Rectangle); 
     if (DropShadowVisible) 
     { 
      shadowRec = Rectangle.FromLTRB(DropShadowThickness, DropShadowThickness, this.ClientRectangle.Right - 1, this.ClientRectangle.Bottom - 1); 
      frameRec = Rectangle.FromLTRB(0, 0, this.ClientRectangle.Right - DropShadowThickness - 2, this.ClientRectangle.Bottom - DropShadowThickness - 2); 
     } 
     else 
     { 
      frameRec = Rectangle.FromLTRB(this.ClientRectangle.Left, this.ClientRectangle.Top, this.ClientRectangle.Right - 1, this.ClientRectangle.Bottom - 1); 
     } 

     if (frameRec.Height <= 0 | frameRec.Width <= 0) 
      return; 

     //draw the drop shadow using the shadow path rectangle 
     if (DropShadowVisible) 
     { 
      using (GraphicsPath path = GraphicsFunctions.RoundRectangle(shadowRec, _CornerRadius, _Corners)) 
      { 
       using (SolidBrush b = new SolidBrush(_ShadowColor)) 
       { 
        e.Graphics.FillPath(b, path); 
       } 
      } 
     } 

     //draw the rest of the control in the main frame path 
     using (GraphicsPath path = GraphicsFunctions.RoundRectangle(frameRec, _CornerRadius, _Corners)) 
     { 
      //paint the background inside the frame 
      if (BackgroundGradientMode == ControlGradientMode.None) 
      { 
       //solid background 
       using (SolidBrush b = new SolidBrush(BackgroundColor)) 
       { 
        e.Graphics.FillPath(b, path); 
       } 
      } 
      else 
      { 
       //gradient 
       if (BackgroundGradientMode == ControlGradientMode.VerticalGlow) 
       { 
        using (LinearGradientBrush b = new LinearGradientBrush(new Point(0, frameRec.Top + (frameRec.Height/2)), new Point(0, frameRec.Bottom - 1), BackgroundColorGradient, BackgroundColor)) 
        { 

         b.WrapMode = WrapMode.TileFlipXY; 
         e.Graphics.FillPath(b, path); 
        } 
       } 
       else if (BackgroundGradientMode == ControlGradientMode.HorizontalGlow) 
       { 
        using (LinearGradientBrush b = new LinearGradientBrush(new Point(frameRec.Left + (frameRec.Width/2), 0), new Point(frameRec.Right - 1, 0), BackgroundColorGradient, BackgroundColor)) 
        { 

         b.WrapMode = WrapMode.TileFlipXY; 
         e.Graphics.FillPath(b, path); 
        } 
       } 
       else 
       { 
        using (LinearGradientBrush br = new LinearGradientBrush(frameRec, BackgroundColor, BackgroundColorGradient, (LinearGradientMode)BackgroundGradientMode)) 
        { 
         e.Graphics.FillPath(br, path); 
        } 
       } 

       // 
       using (SolidBrush b = new SolidBrush(ForeColor)) 
       { 
        StringFormat sf = new StringFormat(); 
        //Rectangle textRec = default(Rectangle); 


        switch (this.TextAlign) 
        { 
         case ContentAlignment.BottomCenter: 
          sf.Alignment = StringAlignment.Center; 
          sf.LineAlignment = StringAlignment.Far; 
          break; 
         case ContentAlignment.BottomLeft: 
          sf.Alignment = StringAlignment.Near; 
          sf.LineAlignment = StringAlignment.Far; 
          break; 
         case ContentAlignment.BottomRight: 
          sf.Alignment = StringAlignment.Far; 
          sf.LineAlignment = StringAlignment.Far; 
          break; 
         case ContentAlignment.MiddleCenter: 
          sf.Alignment = StringAlignment.Center; 
          sf.LineAlignment = StringAlignment.Center; 
          break; 
         case ContentAlignment.MiddleLeft: 
          sf.Alignment = StringAlignment.Near; 
          sf.LineAlignment = StringAlignment.Center; 
          break; 
         case ContentAlignment.MiddleRight: 
          sf.Alignment = StringAlignment.Far; 
          sf.LineAlignment = StringAlignment.Center; 
          break; 
         case ContentAlignment.TopCenter: 
          sf.Alignment = StringAlignment.Center; 
          sf.LineAlignment = StringAlignment.Near; 
          break; 
         case ContentAlignment.TopLeft: 
          sf.Alignment = StringAlignment.Near; 
          sf.LineAlignment = StringAlignment.Near; 
          break; 
         case ContentAlignment.TopRight: 
          sf.Alignment = StringAlignment.Far; 
          sf.LineAlignment = StringAlignment.Near; 
          break; 
        } 


        sf.Alignment = StringAlignment.Center; 
        e.Graphics.DrawString(this.Text, this.Font, b, (RectangleF)frameRec, sf); 
        Invalidate(); 
       } 
       Invalidate(); 
      } 

      e.Graphics.ResetTransform(); 
      //draw the border 
      using (Pen p = new Pen(BorderColor, BorderWidth)) 
      { 
       e.Graphics.DrawPath(p, path); 
      } 
     } 
    } 
} 

它有這種依賴(對不起相當長的!):我使用的將它添加到一個表單

[Flags()] 
public enum RoundedControlCorners 
{ 
    None = 0, 
    NorthWest = 2, 
    NorthEast = 4, 
    SouthEast = 8, 
    SouthWest = 16, 
    All = NorthWest | NorthEast | SouthEast | SouthWest, 
    North = NorthWest | NorthEast, 
    South = SouthEast | SouthWest, 
    East = NorthEast | SouthEast, 
    West = NorthWest | SouthWest 
} 

public enum ControlGradientMode 
{ 
    /// <summary>Specifies no gradient mode.</summary> 
    None = 4, 

    /// <summary>Specifies a gradient from upper right to lower left.</summary> 
    BackwardDiagonal = LinearGradientMode.BackwardDiagonal, 

    /// <summary>Specifies a gradient from upper left to lower right.</summary> 
    ForwardDiagonal = LinearGradientMode.ForwardDiagonal, 

    /// <summary>Specifies a gradient from left to right.</summary> 
    Horizontal = LinearGradientMode.Horizontal, 

    /// <summary>Specifies a gradient from top to bottom.</summary> 
    Vertical = LinearGradientMode.Vertical, 

    VerticalGlow = 5, 
    HorizontalGlow = 6 
} 

public static class GraphicsFunctions 
{ 
    public static GraphicsPath RoundRectangle(Rectangle r, int radius, RoundedControlCorners corners) 
    { 
     GraphicsPath path = new GraphicsPath(); 
     if (r.Width <= 0 | r.Height <= 0) 
      return path; 

     int d = radius * 2; 

     int nw = ((corners & RoundedControlCorners.NorthWest) == RoundedControlCorners.NorthWest ? d : 0); 
     int ne = ((corners & RoundedControlCorners.NorthEast) == RoundedControlCorners.NorthEast ? d : 0); 
     int se = ((corners & RoundedControlCorners.SouthEast) == RoundedControlCorners.SouthEast ? d : 0); 
     int sw = ((corners & RoundedControlCorners.SouthWest) == RoundedControlCorners.SouthWest ? d : 0); 

     //path.AddLine(r.Left + nw, r.Top, r.Right - ne, r.Top); 
     path.AddLine(r.Left + nw, r.Top, r.Right - ne, r.Top); 

     if (ne > 0) 
     { 
      path.AddArc(Rectangle.FromLTRB(r.Right - ne, r.Top, r.Right, r.Top + ne), -90, 90); 
     } 

     path.AddLine(r.Right, r.Top + ne, r.Right, r.Bottom - se); 

     if (se > 0) 
     { 
      path.AddArc(Rectangle.FromLTRB(r.Right - se, r.Bottom - se, r.Right, r.Bottom), 0, 90); 
     } 

     path.AddLine(r.Right - se, r.Bottom, r.Left + sw, r.Bottom); 

     if (sw > 0) 
     { 
      path.AddArc(Rectangle.FromLTRB(r.Left, r.Bottom - sw, r.Left + sw, r.Bottom), 90, 90); 
     } 

     path.AddLine(r.Left, r.Bottom - sw, r.Left, r.Top + nw); 

     if (nw > 0) 
     { 
      path.AddArc(Rectangle.FromLTRB(r.Left, r.Top, r.Left + nw, r.Top + nw), 180, 90); 
     } 

     path.CloseFigure(); 
     return path; 
    } 
} 

代碼:

LabelEx oLabel1 = new LabelEx(); 
LabelEx oLabel2 = new LabelEx(); 
LabelEx oLabel3 = new LabelEx(); 

oLabel1.Top = 50; 
oLabel2.Top = 100; 
oLabel3.Top = 150; 

oLabel1.Height = 25; 
oLabel2.Height = 25; 

oLabel1.Text = "Hello"; 
oLabel2.Text = "There"; 

scBase.Panel2.Controls.Add(oLabel1); 
scBase.Panel2.Controls.Add(oLabel2); 

回答

5
protected override void OnPaint(PaintEventArgs e) 
{ 
    //... 
      Invalidate(); 
} 

一個很好的實踐了ny程序員將始終運行任務管理器。我始終保持最小化到通知區域。對我的機器上發生的事情進行鳥瞰,快速點擊以激活它。

這很快發現你的程序有什麼問題,它正在燃燒100%的核心。這是因爲您在OnPaint()方法中調用Invalidate(),立即使您所繪的內容無效。這有幾個副作用,因爲你看到你的程序永遠不會閒置,並在處理器內核上繼續運行代碼。因爲Windows會一直重複生成繪畫事件。

另外,只有一個標籤控制可以被繪製。第一個,Z順序中最低的。因爲在完成繪畫之後,由於Invalidate()調用,下一個繪畫請求再次用於同一個標籤。

刪除Invalidate()調用來解決您的問題,有兩個。

+0

啊 - 簡單!謝謝你的解釋。非常感激。 – ainwood

相關問題