Winforms中的RadioButtonGroup

时间:2017-12-06 15:49:40

标签: c# .net winforms .net-4.0

我正在尝试创建Bootstrap 4 Radio Button Group熟悉的用户体验。 我知道我可以改变Appearance=Button,但这不会给我带来预期的效果。

这就是我得到的:

enter image description here

这就是我想要的:

enter image description here

我找到similar question,但它使用WPF,我需要WinForms。 Second one建议使用列表视图,但该问题列表是垂直的,但我需要水平对齐。

我正在寻找一个控件,左边第一个按钮,右边第一个按钮(就像在第二个图像上一样)

我的问题是:有谁知道这种控制是否存在?如果是的话,我会感激anu链接,如果没有,那么欢迎任何有关如何创建此类控件的提示(我知道如何创建自定义控件并绘制它们,因此不需要如何开始使用用户控件的链接)

修改
因为我的问题被投票,我正在添加我编写的代码来创建这样的控件。 这是我得到的结果:

enter image description here

这是代码:

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 => new Size(200, 30);

        private int _cornerRadius = 2;

        public int CornerRadius
        {
            get => _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 => _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 => _selectedIndex;
            set
            {
                if(value==_selectedIndex) return;
                _selectedIndex = value;
                Invalidate();
            }
        }


        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            _click = true;

            if (_hoverPos > -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 > _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 > -1 || _selectedIndex>-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 > -1 && _selectedIndex != _hoverPos)
                {
                    using (GraphicsPath path = RoundedRect(rect2, _cornerRadius, flags))
                    {

                        e.Graphics.FillPath(_click ? Brushes.SteelBlue : hoverBlush, path);
                    }
                }

                if (_selectedIndex > -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 <= _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 < _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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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;
        }
    }
}

它没有经过优化,只是证明了它的概念。

这个问题的重点是找到现有的控制而不需要重新发明轮子。
如果我无法找到这样的控件,我将创建一个并共享它。

0 个答案:

没有答案