Roman Ratskey Roman Ratskey - 2 months ago 23
C# Question

Drawing border around control

Well, i wanted to draw a custom border around a panel control, and i found that it can be easily achieved using

ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
Color.Indigo, 10, ButtonBorderStyle.Solid,
Color.Indigo, 10, ButtonBorderStyle.Solid,
Color.Indigo, 10, ButtonBorderStyle.Solid,
Color.Indigo, 10, ButtonBorderStyle.Solid);


However, this method and all the other methods i have tried actually draw the border inside the panel so when i dock some control inside it, the control hides the border.

enter image description here

So i wonder is there a way to draw the border outside the control to avoid this problem?

Answer

There are couples of solution however I think this is the simplest solution, you have to be ensure your panel is placed on another container which makes enough room for its outer border.

public class XPanel : Panel {
   public XPanel(){
     BorderWidth = 5;
   }
   Control previousParent;
   public float BorderWidth {get;set;}
   protected override void OnParentChanged(EventArgs e){
     base.OnParentChanged(e);
     if(Parent != previousParent){
       if(Parent != null) Parent.Paint += ParentPaint;
       if(previousParent != null) previousParent.Paint -= ParentPaint;
       previousParent = Parent;
     }
   }
   private void ParentPaint(object sender, PaintEventArgs e){
     using(Pen p = new Pen(Color.Blue, BorderWidth))
     using(var gp = new GraphicsPath())
     {
       float halfPenWidth = BorderWidth / 2;
       var borderRect = new RectangleF(Left - halfPenWidth, Top - halfPenWidth,
                                      Width + BorderWidth, Height + BorderWidth);
       gp.AddRectangle(borderRect);
       e.Graphics.DrawPath(p,gp);
     }
   }
   protected override void OnSizeChanged(EventArgs e){
      base.OnSizeChanged(e);
      if(Parent!=null) Parent.Invalidate();
   }
   protected override void OnLocationChanged(EventArgs e){
      base.OnLocationChanged(e);
      if(Parent != null) Parent.Invalidate();
   }
}

Note that the border drawing code now has to draw on the parent of your panel, you have to adjust the border Rectangle accordingly (it's of course larger than the border drawn inside your panel).

Also note that, because of drawing on the parent, when your panel's size or location is changed, we need to invalidate the parent to redraw correctly. The Invalidate() method can accept a Rectangle to just invalidate on that rectangle, you can calculate your border Rectangle to draw and also to pass in that Invalidate method to improve the performance of drawing a little (mainly helpful to prevent flicker).

Comments