# A Modified GroupBox Control in C#



## Kreij (Sep 16, 2008)

If you have been reading the latest stuff I posted you will know that I have been playing around writing custom controls.
This time I decided to modify the typical GroupBox control. It is kind of bland after all.

My new control does the following
(I'm not listing the basic GroupBox stuff. It's a container for other controls, just like usual)

Allows for an optional title (title area does not draw if no title given)
Allows an optional adjustable width border (of any color) around the group and title areas.
Allows for optional, adjustable rounded corners on both the group and title areas.
Allows an optional adjustable drop shadow (of any color) around the group and titles areas.
Allows the group and title background area to be filled with either a solid color, gradient color, or image.
Alllows for an optional Icon in the title area.

Similar to the last controls I did, I override the paint method and call my own custom methods.
In this case there are two. PaintGroupBackground() and PaintTitleBackground()

The one thing I would like to point out is that VS makes it easy to create a control that can contain other controls.
All you have to do is place a single line above your class declaration.

```
[[color=teal]Designer[/color]([color=red]"ParentControlDesigner, Design"[/color], [color=blue]typeof[/color]([color=teal]IDesigner[/color]))]
[color=blue]public partial class[/color] [color=teal]NFXGroupContainer[/color] : [color=teal]UserControl[/color]
```

I'm not going to go into detail on the code, as it is mostly just drawing stuff like creating arcs and such.

Here is a picture of the control running in the TestContainer utility that comes with VS;
It has a title, gradient background for title, title Icon, title and group rounded borders, title and group drop shadows and a group image. It does not contain any child controls in it.







Here is the complete code for the control. (I haven't done complete testing, but it should be pretty solid)

```
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace NFXControls
{
    [Designer("ParentControlDesigner, Design", typeof(IDesigner))]
    public partial class NFXGroupContainer : UserControl
    {
        private Color backgroundColor = Color.White;
        private Boolean hasBackgroundImage = true;
        private Image backgroundImage = Image.FromFile("bullets.jpg");
        private Boolean hasBackgroundGradient = false;
        private Color backgroundGradientColor = Color.Teal;
        private LinearGradientMode backgroundGradientMode = LinearGradientMode.Horizontal;
        private Boolean hasBackgroundDropShadow = true;
        private Color backgroundDropShadowColor = Color.Gray;
        private int backgroundDropShadowWidth = 6;
        private Boolean hasBackgroundBorder = true;
        private Color backgroundBorderColor = Color.Black;
        private int backgroundBorderWidth = 1;

        private Color titleColor = Color.White;
        private Boolean hasTitleImage = false;
        private Image titleImage;
        private Boolean hasTitleGradient = true;
        private Color titleGradientColor = Color.Silver;
        private LinearGradientMode titleGradientMode = LinearGradientMode.Horizontal;
        private Boolean hasTitleDropShadow = true;
        private Color titleDropShadowColor = Color.Gray;
        private int titleDropShadowWidth = 3;
        private Boolean hasTitleBorder = true;
        private Color titleBorderColor = Color.Black;
        private int titleBorderWidth = 1;
        private Boolean hasTitleIcon = true;
        private Icon titleIcon = new Icon(@".\TPU.ico");
        private String title = "TPU Hit Squad Members";
        private Color titleTextColor = Color.Black;

        private GraphicsPath backgroundPath;
        private GraphicsPath backgroundDropShadowPath;
        private GraphicsPath titlePath;
        private GraphicsPath titleDropShadowPath;

        private int roundOver = 16;
        private int titleRoundOver;

        private int BGTopX, BGTopY;
        private int BGBottomX, BGBottomY;
        private int TitleTopX, TitleTopY;
        private int TitleBottomX, TitleBottomY;
        

        public NFXGroupContainer()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                 ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.SupportsTransparentBackColor | 
                 ControlStyles.UserPaint, true);
        }

        #region Control Properties

        #region Background Properties

        [Category("Appearance")]
        public Color GroupBackgroundColor
        {
            get { return backgroundColor; }
            set { backgroundColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasBackgroundImage
        {
            get { return hasBackgroundImage; }
            set { hasBackgroundImage = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Image GroupBackgroundImage
        {
            get { return backgroundImage; }
            set { backgroundImage = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasBackgroundGradient
        {
            get { return hasBackgroundGradient; }
            set { hasBackgroundGradient = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color GroupBackgroundGradientColor
        {
            get { return backgroundGradientColor; }
            set { backgroundGradientColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public LinearGradientMode GroupBackgroundGradientMode
        {
            get { return backgroundGradientMode; }
            set { backgroundGradientMode = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasBackgroundDropShadow
        {
            get { return hasBackgroundDropShadow; }
            set { hasBackgroundDropShadow = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color GroupBackgroundDropShadowColor
        {
            get { return backgroundDropShadowColor; }
            set { backgroundDropShadowColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public int GroupBackgroundDropShadowWidth
        {
            get { return backgroundDropShadowWidth; }
            set { backgroundDropShadowWidth = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasBackgroundBorder
        {
            get { return hasBackgroundBorder; }
            set { hasBackgroundBorder = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color GroupBackgroundBorderColor
        {
            get { return backgroundBorderColor; }
            set { backgroundBorderColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public int GroupBackgroundBorderWidth
        {
            get { return backgroundBorderWidth; }
            set { backgroundBorderWidth = value; this.Invalidate(); }
        }
        
        #endregion Background Poperties

        #region Title Properties

        [Category("Appearance")]
        public Color TitleColor
        {
            get { return titleColor; }
            set { titleColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasTitleImage
        {
            get { return hasTitleImage; }
            set { hasTitleImage = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Image TitleImage
        {
            get { return titleImage; }
            set { titleImage = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasTitleGradient
        {
            get { return hasTitleGradient; }
            set { hasTitleGradient = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color TitleGradientColor
        {
            get { return titleGradientColor; }
            set { titleGradientColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public LinearGradientMode TitleGradientMode
        {
            get { return titleGradientMode; }
            set { titleGradientMode = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasTitleDropShadow
        {
            get { return hasTitleDropShadow; }
            set { hasTitleDropShadow = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color TitleDropShadowColor
        {
            get { return titleDropShadowColor; }
            set { titleDropShadowColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public int TitleDropShadowWidth
        {
            get { return titleDropShadowWidth; }
            set { titleDropShadowWidth = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasTitleBorder
        {
            get { return hasTitleBorder; }
            set { hasTitleBorder = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Color TitleBorderColor
        {
            get { return titleBorderColor; }
            set { titleBorderColor = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public int TitleBorderWidth
        {
            get { return titleBorderWidth; }
            set { titleBorderWidth = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Boolean HasTitleIcon
        {
            get { return hasTitleIcon; }
            set { hasTitleIcon = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        public Icon TitleIcon
        {
            get { return titleIcon; }
            set { titleIcon = value; this.Invalidate(); }
        }

        [Category("Appearance")]
        private String Title
        {
            get { return title; }
            set { title = value; this.Invalidate(); }
        }

        #endregion Title Properties

        [Category("Appearance")]
        public int RoundOver
        {
            get { return roundOver; }
            set { roundOver = value; }
        }

        #endregion Control Properties

        private void SetupGroupArcs()
        {
            BGTopX = 0;
            BGTopY = 10;
            BGBottomX =
                (hasBackgroundDropShadow ?
                (this.Width - (roundOver + 1)) - backgroundDropShadowWidth :
                (this.Width - (roundOver + 1)));
            BGBottomY =
                (hasBackgroundDropShadow ?
                (this.Height - (roundOver + 1)) - backgroundDropShadowWidth :
                (this.Height - (roundOver + 1)));

            
        }

        private void SetupTitleArcs(int titleWidth)
        {
            titleRoundOver = (roundOver > 8 ? 17 : roundOver + 1);
            int AdjustedWidth = ((titleWidth + 30) +
                (hasTitleIcon ? 20 : 0)) - titleRoundOver;

            TitleTopX = 25;
            TitleTopY = 0;
            TitleBottomX =
                (hasTitleDropShadow ?
                AdjustedWidth - titleDropShadowWidth :
                AdjustedWidth);
            TitleBottomY =
                (hasTitleDropShadow ?
                (24 - titleRoundOver) - titleDropShadowWidth :
                (24 - titleRoundOver));
        }

        private GraphicsPath CreateBackgroundDropShadowPath()
        {
            GraphicsPath gp = new GraphicsPath();
            gp.AddArc(BGTopX + backgroundDropShadowWidth,
                BGTopY + backgroundDropShadowWidth, roundOver, roundOver, 180, 90);
            gp.AddArc(BGBottomX + backgroundDropShadowWidth,
                BGTopY + backgroundDropShadowWidth, roundOver, roundOver, 270, 90);
            gp.AddArc(BGBottomX + backgroundDropShadowWidth,
                BGBottomY + backgroundDropShadowWidth, roundOver, roundOver, 360, 90);
            gp.AddArc(BGTopX + backgroundDropShadowWidth,
                BGBottomY + backgroundDropShadowWidth, roundOver, roundOver, 90, 90);
            gp.CloseAllFigures();
            return gp;
        }

        private GraphicsPath CreateBackgroundPath()
        {
            GraphicsPath gp = new GraphicsPath();
            gp.AddArc(BGTopX, BGTopY, roundOver, roundOver, 180, 90);
            gp.AddArc(BGBottomX, BGTopY, roundOver, roundOver, 270, 90);
            gp.AddArc(BGBottomX, BGBottomY, roundOver, roundOver, 360, 90);
            gp.AddArc(BGTopX, BGBottomY, roundOver, roundOver, 90, 90);
            gp.CloseAllFigures();

            return gp;
        }

        private GraphicsPath CreateTitleDropShadowPath()
        {
            GraphicsPath gp = new GraphicsPath();
            gp.AddArc(TitleTopX + titleDropShadowWidth,
                TitleTopY + titleDropShadowWidth,
                titleRoundOver, titleRoundOver, 180, 90);
            gp.AddArc(TitleBottomX + titleDropShadowWidth,
                TitleTopY + titleDropShadowWidth,
                titleRoundOver, titleRoundOver, 270, 90);
            gp.AddArc(TitleBottomX + titleDropShadowWidth,
                TitleBottomY + titleDropShadowWidth,
                titleRoundOver, titleRoundOver, 360, 90);
            gp.AddArc(TitleTopX + titleDropShadowWidth,
                TitleBottomY + titleDropShadowWidth,
                titleRoundOver, titleRoundOver, 90, 90);
            gp.CloseAllFigures();
            return gp;
        }

        private GraphicsPath CreateTitlePath()
        {
            GraphicsPath gp = new GraphicsPath();
            gp.AddArc(TitleTopX, TitleTopY,
                titleRoundOver, titleRoundOver, 180, 90);
            gp.AddArc(TitleBottomX, TitleTopY,
                titleRoundOver, titleRoundOver, 270, 90);
            gp.AddArc(TitleBottomX, TitleBottomY,
                titleRoundOver, titleRoundOver, 360, 90);
            gp.AddArc(TitleTopX, TitleBottomY,
                titleRoundOver, titleRoundOver, 90, 90);
            gp.CloseAllFigures();

            return gp;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            PaintGroupBackground(e.Graphics);
            if (title.Length != 0) PaintTitleBackground(e.Graphics);
        }

        private void PaintGroupBackground(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;

            SetupGroupArcs();
            if (hasBackgroundDropShadow) backgroundDropShadowPath =
                CreateBackgroundDropShadowPath();
            backgroundPath = CreateBackgroundPath();

            if (hasBackgroundDropShadow)
            {
                using (Brush DropShadowBrush = new SolidBrush(backgroundDropShadowColor))
                {
                    g.FillPath(DropShadowBrush, backgroundDropShadowPath);
                }
            }

            if (hasBackgroundGradient)
            {
                using (Brush GradientBrush = new LinearGradientBrush(
                    new Rectangle(0, 0, this.Width, this.Height), backgroundColor, 
                    backgroundGradientColor, backgroundGradientMode))
                {
                    g.FillPath(GradientBrush, backgroundPath);
                }
            }
            else
            {
                using (Brush BackgroundBrush = new SolidBrush(backgroundColor))
                {
                    g.FillPath(BackgroundBrush, backgroundPath);
                }
            }

            if (hasBackgroundImage)
            {
                g.SetClip(backgroundPath);
                g.DrawImage(backgroundImage, Rectangle.Round(backgroundPath.GetBounds()));
                g.ResetClip();
            }

            if (hasBackgroundBorder)
            {
                using (Pen BorderPen =
                    new Pen(backgroundBorderColor, (float)backgroundBorderWidth))
                {
                    g.DrawPath(BorderPen, backgroundPath);
                }
            }
        }

        private void PaintTitleBackground(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = TextRenderingHint.AntiAlias;

            SizeF TitleSize = g.MeasureString(title, Font);

            SetupTitleArcs((titleIcon != null ? 
                (int)(TitleSize.Width) + 20 : (int)TitleSize.Width));

            if (hasTitleDropShadow) titleDropShadowPath = CreateTitleDropShadowPath();
            titlePath = CreateTitlePath();

            if (hasTitleDropShadow)
            {
                using (Brush DropShadowBrush = new SolidBrush(titleDropShadowColor))
                {
                    g.FillPath(DropShadowBrush, titleDropShadowPath);
                }
            }

            if (hasTitleGradient)
            {
                using (Brush GradientBrush = new LinearGradientBrush(
                    Rectangle.Round(titlePath.GetBounds()),
                    titleGradientColor, titleColor, titleGradientMode))
                {
                    g.FillPath(GradientBrush, titlePath);
                }
                   
            }
            else
            {
                using (Brush TitleBrush = new SolidBrush(titleColor))
                {
                    g.FillPath(TitleBrush, titlePath);
                }
            }

            if (hasTitleIcon)
            {
                Rectangle rt = Rectangle.Round(titlePath.GetBounds());
                g.DrawIcon(titleIcon, rt.Left + 7, rt.Top + 3);
            }

            using (Font titleFont = new Font(Font, FontStyle.Regular))
            {
                TextRenderer.DrawText(g, title, titleFont,
                    Rectangle.Round(titlePath.GetBounds()), titleTextColor,
                    TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
            }

            if (hasTitleImage)
            {
                g.SetClip(titlePath);
                g.DrawImage(titleImage, Rectangle.Round(titlePath.GetBounds()));
                g.ResetClip();
            }

            if (hasTitleBorder)
            {
                using (Pen BorderPen = new Pen(titleBorderColor, titleBorderWidth))
                {
                    g.DrawPath(BorderPen, titlePath);
                }
            }
        }
    }
}
```

Just another little exercise to show everyone that you can do anything you want with the look, feel and behavior of custom controls.
As always, if you have any questions , comments or code corrections please post.

I addition, I would like to thank Adam Smith and his Grouper Control over at C# Corner for my initial inspiration.

Happy Coding !


----------

