简体   繁体   中英

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.

在此处输入图片说明

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

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).

There is a BorderStyle property on the Panel control. Your options there are limited with that though.

The reason that you are losing the border that you're drawing is because what your drawing is inside the panel's space.

You have two options to get what you desire.

1) The far easiest way to get what you want would be to stack panels. Have the one in the back have a background color of whatever you want the border to be. Then put another panel inside of that panel with a border of whatever width you want the border to be. (If you want a 4px border on all sides, the "inner"/"top" panel will be 8px smaller on the width and height).

2) Add functionality to the Panel object to draw the border how you want. But this would be an awful lot of work.

Dirty and easy solution. Based on krillgar's and King King's answers.

You can create own Panel , which will hold another Panel inside (create it in the constructor) and forward all ControlAdded / ControlRemoved to it, while positioning it perfectly inside. This way you can keep drawing border as you do now.

Rather than an ugly workaround for not being able to paint outside your area, you can instead just keep things inside your border; so don't use docking, use anchor.

Ex:

Controls.Add(mScrollBar);
int borderSize = 1; // some border size

mScrollBar.SetBounds(
   Right - mScrollBar.Width - borderSize, // x; from the right, the width and the border
   borderSize,                            // y; from the top, just the border
   mScrollBar.Width,                      // width can stay the same
   Height - borderSize * 2                // height minus two borders
);

mScrollBar.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM