title: RadioButtonGroup in Winforms
body: <p>I'm trying to create UX that is familiar to <a href="https://getbootstrap.com/docs/4.0/components/buttons/#checkbox-and-radio-buttons" rel="nofollow noreferrer">Bootstrap 4 Radio Button Group</a>. 
  I know I can change <code>Appearance=Button</code> but this wont give me desired effect.</p>
  
  <p>This is what I get:</p>
  
  <p><a href="https://i.stack.imgur.com/k5UKY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/k5UKY.png" alt="enter image description here"></a></p>
  
  <p>and this is what I want:</p>
  
  <p><a href="https://i.stack.imgur.com/zlIUM.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zlIUM.png" alt="enter image description here"></a></p>
  
  <p>I found <a href="https://stackoverflow.com/questions/8847459/slider-and-radio-button-styling-in-wpf">similar question</a>, but it uses WPF and I need WinForms.
  <a href="https://stackoverflow.com/questions/15500882/winform-radio-button-logic-with-another-look-and-feel">Second one</a> suggest using list view, but in that question list is vertical, but I need horizontal align.</p>
  
  <p>I'm looking for a control that has first button rounded on left and last on right (just like on second image)</p>
  
  <p>My question is: Does anyone know is such control exists? If yes I'll be grateful for anu links, if no then any tips regarding how to create such control are welcome (I know how to create custom controls and paint them so links on how to get started with user controls aren't needed)</p>
  
  <p><strong>EDIT</strong><br>
  Because my question got down voted I'm adding code that I've written to create such control.
  This is result I got:</p>
  
  <p><a href="https://i.stack.imgur.com/6Nn55.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6Nn55.png" alt="enter image description here"></a></p>
  
  <p>and here is code:</p>
  
  <pre><code>using System;
  using System.ComponentModel;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Windows.Forms;
  
  namespace UserControls
  {
      public sealed class RadioGroupBox: UserControl
      {
          public RadioGroupBox()
          {
              DoubleBuffered = true;
              ResizeRedraw = true;
              Padding = new Padding(2);
              CalculateItemWidth();
          }
  
          public event EventHandler SelectedIndexChanged;
  
          protected override Size DefaultSize =&gt; new Size(200, 30);
  
          private int _cornerRadius = 2;
  
          public int CornerRadius
          {
              get =&gt; _cornerRadius;
              set
              {
                  if(value==_cornerRadius) return;
                  _cornerRadius = value;
                  Invalidate();
              }
          }
  
          private string[] _items = {"A", "B", "C"};
          [Category("Data")]
          //[DefaultValue(null)]
          [Description("Items")]
          public string[] Items
          {
              get =&gt; _items;
              set
              {
                  if(value==_items) return;
                  _items = value;
                  CalculateItemWidth();
                  Invalidate();
              }
          }
  
  
  
          private int _itemWidth;
  
          private void CalculateItemWidth()
          {
              if (_items == null || _items.Length == 0)
              {
                  _itemWidth = 0;
                  return;
              }
              var width = ClientRectangle.Width - Padding.Horizontal;
              _itemWidth = width / _items.Length;
  
          }
  
          protected override void OnMouseMove(MouseEventArgs e)
          {
              base.OnMouseMove(e);
  
              CalculateItemWidth();
              //Debug.WriteLine(_itemWidth);
              CalculateSelectedItem(e.Location);
          }
  
          private int _selectedIndex = -1;
          public int SelectedIndex
          {
              get =&gt; _selectedIndex;
              set
              {
                  if(value==_selectedIndex) return;
                  _selectedIndex = value;
                  Invalidate();
              }
          }
  
  
          protected override void OnMouseDown(MouseEventArgs e)
          {
              base.OnMouseDown(e);
              _click = true;
  
              if (_hoverPos &gt; -1)
              {
                  if (_selectedIndex != _hoverPos)
                  {
                      _selectedIndex = _hoverPos;
                      SelectedIndexChanged?.Invoke(this, e);
                  }
              }
              Invalidate();
          }
  
          protected override void OnMouseUp(MouseEventArgs e)
          {
              base.OnMouseUp(e);
              _click = false;
              Invalidate();
          }
  
          private int _hoverPos = -1;
          private bool _click;
  
          private void CalculateSelectedItem(Point mouseLocation)
          {
              var clientRect = GetPaddedRectangle();
              int pos;
              if (!clientRect.Contains(mouseLocation))
              {
                  pos = -1;
              }
              else
              {
                  pos = mouseLocation.X / _itemWidth;
                  if (pos &gt; _items.Length - 1)
                  {
                      pos = -1;
                  }
              }
  
              if (pos != _hoverPos)
              {
                  _hoverPos = pos;
                  Invalidate();
              }
  
              //Debug.WriteLine(_hoverPos);
          }
  
          protected override void OnResize(EventArgs e)
          {
              base.OnResize(e);
              CalculateItemWidth();
          }
  
          protected override void OnPaint(PaintEventArgs e)
          {
              base.OnPaint(e);
              e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
              var rect = GetPaddedRectangle();
  
              LinearGradientBrush normalBrush = new LinearGradientBrush(rect,
                  Color.White, 
                  Color.LightBlue, 
                  LinearGradientMode.Vertical);
              LinearGradientBrush hoverBlush = new LinearGradientBrush(rect,
                  Color.RoyalBlue,
                  Color.MediumBlue,
                  LinearGradientMode.Vertical);
  
              LinearGradientBrush selectedBrush = new LinearGradientBrush(rect,
                  Color.DodgerBlue,
                  Color.Blue,
                  LinearGradientMode.Vertical);
  
              //e.Graphics.FillRectangle(Brushes.Aqua, this.ClientRectangle);
              using (GraphicsPath path = RoundedRect(rect, _cornerRadius))
              {
                  e.Graphics.FillPath(normalBrush, path);
                  e.Graphics.DrawPath(Pens.DodgerBlue, path);
              }
  
              if (_items == null || _items.Length == 0) return;
  
              if (_hoverPos &gt; -1 || _selectedIndex&gt;-1)
              {
                  var flags = RectangleCorners.None;
                  if (_hoverPos == 0) flags = RectangleCorners.TopLeft | RectangleCorners.BottomLeft;
                  if(_hoverPos==_items.Length-1) flags = RectangleCorners.TopRight | RectangleCorners.BottomRight;
                  var rect2 = new Rectangle(rect.X + _hoverPos * _itemWidth, rect.Y, _itemWidth, rect.Height);
                  if (_hoverPos == _items.Length - 1)
                  {
                      rect2 = new Rectangle(rect.X + _hoverPos * _itemWidth, rect.Y, rect.Width-_hoverPos*_itemWidth, rect.Height);
                  }
  
                  if (_hoverPos &gt; -1 &amp;&amp; _selectedIndex != _hoverPos)
                  {
                      using (GraphicsPath path = RoundedRect(rect2, _cornerRadius, flags))
                      {
  
                          e.Graphics.FillPath(_click ? Brushes.SteelBlue : hoverBlush, path);
                      }
                  }
  
                  if (_selectedIndex &gt; -1)
                  {
                      rect2 = new Rectangle(rect.X + _selectedIndex * _itemWidth, rect.Y, _itemWidth, rect.Height);
                      if (_selectedIndex == _items.Length - 1)
                      {
                          rect2 = new Rectangle(rect.X + _selectedIndex * _itemWidth, rect.Y, rect.Width - _selectedIndex * _itemWidth, rect.Height);
                      }
  
                      flags = RectangleCorners.None;
                      if (_selectedIndex == 0) flags = RectangleCorners.TopLeft | RectangleCorners.BottomLeft;
                      if (_selectedIndex == _items.Length - 1) flags = RectangleCorners.TopRight | RectangleCorners.BottomRight;
  
                      using (GraphicsPath path = RoundedRect(rect2, _cornerRadius, flags))
                      {
  
                          e.Graphics.FillPath(selectedBrush, path);
                      }
                  }
              }
  
              //pionowe linie
  
              for (int i = 1; i &lt;= _items.Length-1; i++)
              {
                  e.Graphics.DrawLine(Pens.DodgerBlue,rect.X+i*_itemWidth,rect.Y, rect.X + i * _itemWidth, rect.Y+rect.Height);
              }
  
  
              StringFormat sf = new StringFormat
              {
                  LineAlignment = StringAlignment.Center,
                  Alignment = StringAlignment.Center
              };
  
              for (var i = 0; i &lt; _items.Length; i++)
              {
                  string item = _items[i];
                  e.Graphics.DrawString(item, Font, i==_hoverPos?Brushes.White:Brushes.DodgerBlue, new Rectangle(rect.X+i* _itemWidth, rect.Y, _itemWidth, rect.Height), sf);
  
              }      
  
              //Debug.WriteLine(MousePosition);
          }
  
          private Rectangle GetPaddedRectangle()
          {
              var rect = ClientRectangle;
              var pad = Padding;
              return new Rectangle(rect.X + pad.Left,
                  rect.Y + pad.Top,
                  rect.Width - pad.Horizontal,
                  rect.Height - pad.Vertical);
          }
  
          [Flags]
          public enum RectangleCorners
          {
              None = 0, TopLeft = 1, TopRight = 2, BottomLeft = 4, BottomRight = 8,
              All = TopLeft | TopRight | BottomLeft | BottomRight
          }
  
          public static GraphicsPath RoundedRect(Rectangle bounds, int radius, RectangleCorners corners = RectangleCorners.All)
          {
              int diameter = radius * 2;
              GraphicsPath path = new GraphicsPath();
  
              if (radius == 0)
              {
                  path.AddRectangle(bounds);
                  return path;
              }
  
              // Make a GraphicsPath to draw the rectangle.
              PointF point1, point2;
  
              // Upper left corner.
              if ((RectangleCorners.TopLeft &amp; corners) == RectangleCorners.TopLeft)
              {
                  RectangleF corner = new RectangleF(bounds.X, bounds.Y,diameter, diameter);
                  path.AddArc(corner, 180, 90);
                  point1 = new PointF(bounds.X + radius, bounds.Y);
              }
              else point1 = new PointF(bounds.X, bounds.Y);
  
              // Top side.
              if ((RectangleCorners.TopRight &amp; corners) == RectangleCorners.TopRight)
                  point2 = new PointF(bounds.Right - radius, bounds.Y);
              else
                  point2 = new PointF(bounds.Right, bounds.Y);
              path.AddLine(point1, point2);
  
              // Upper right corner.
              if ((RectangleCorners.TopRight &amp; corners) == RectangleCorners.TopRight)
              {
                  RectangleF corner = new RectangleF(bounds.Right - diameter, bounds.Y,diameter, diameter);
                  path.AddArc(corner, 270, 90);
                  point1 = new PointF(bounds.Right, bounds.Y + radius);
              }
              else point1 = new PointF(bounds.Right, bounds.Y);
  
              // Right side.
              if ((RectangleCorners.BottomRight &amp; corners) == RectangleCorners.BottomRight)
                  point2 = new PointF(bounds.Right, bounds.Bottom - radius);
              else
                  point2 = new PointF(bounds.Right, bounds.Bottom);
              path.AddLine(point1, point2);
  
              // Lower right corner.
              if ((RectangleCorners.BottomRight &amp; corners) == RectangleCorners.BottomRight)
              {
                  RectangleF corner = new RectangleF(bounds.Right - diameter,bounds.Bottom - diameter,diameter, diameter);
                  path.AddArc(corner, 0, 90);
                  point1 = new PointF(bounds.Right - radius, bounds.Bottom);
              }
              else point1 = new PointF(bounds.Right, bounds.Bottom);
  
              // Bottom side.
              if ((RectangleCorners.BottomLeft &amp; corners) == RectangleCorners.BottomLeft)
                  point2 = new PointF(bounds.X + radius, bounds.Bottom);
              else
                  point2 = new PointF(bounds.X, bounds.Bottom);
              path.AddLine(point1, point2);
  
              // Lower left corner.
              if ((RectangleCorners.BottomLeft &amp; corners) == RectangleCorners.BottomLeft)
              {
                  RectangleF corner = new RectangleF(bounds.X, bounds.Bottom - diameter,diameter, diameter);
                  path.AddArc(corner, 90, 90);
                  point1 = new PointF(bounds.X, bounds.Bottom - radius);
              }
              else point1 = new PointF(bounds.X, bounds.Bottom);
  
              // Left side.
              if ((RectangleCorners.TopLeft &amp; corners) == RectangleCorners.TopLeft)
                  point2 = new PointF(bounds.X, bounds.Y + radius);
              else
                  point2 = new PointF(bounds.X, bounds.Y);
              path.AddLine(point1, point2);
  
              // Join with the start point.
              path.CloseFigure();
  
              return path;
          }
      }
  }
  </code></pre>
  
  <p>it isn't optimized, it's just prove of concept.</p>
  
  <p><strong>Whole point of this question is to find existing control without need to reinvent the wheel.</strong><br>
  If I won't be able to find such control I'll create one and share it.</p>