C#窗体实现自定义数字控件
窗体项目需求
显示设备名称和数字控件1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace CCIMS
{/// <summary>/// 水平布局通道进场人数自定义控件/// </summary>[DefaultProperty("ChannelName")][DefaultEvent("Click")]public partial class HorizontalChannelControl : UserControl{#region 字段private string _channelName = "通道";private string _channelIpAddress = "127.0.0.1";private int _entryCount = 0;private Color _channelNameColor = Color.FromArgb(255, 255, 255); // 白色private Color _countColor = Color.FromArgb(79, 172, 254); // 蓝色private Color _labelColor = Color.FromArgb(180, 180, 180); // 灰色标签private Color _backgroundColor = Color.FromArgb(50, 50, 60);private Color _hoverColor = Color.FromArgb(70, 70, 80);private Color _borderColor = Color.FromArgb(80, 80, 100);private Font _channelFont = new Font("微软雅黑", 12, FontStyle.Bold);private Font _countFont = new Font("微软雅黑", 12, FontStyle.Bold);private Font _labelFont = new Font("微软雅黑", 12, FontStyle.Regular);private bool _isHovered = false;private int _borderRadius = 6;private bool _showBorder = true;private string _labelText = "进场";#endregion#region 属性[Category("数据")][Description("通道名称")]public string ChannelName{get { return _channelName; }set{_channelName = value;Invalidate();}}[Category("数据")][Description("通道Ip地址")]public string ChannelNameIpAddress{get { return _channelIpAddress; }set{_channelIpAddress = value;}}[Category("数据")][Description("进场人数")]public int EntryCount{get { return _entryCount; }set{if (value != _entryCount){_entryCount = Math.Max(0, value);Invalidate();OnEntryCountChanged(EventArgs.Empty);}}}[Category("外观")][Description("通道名称颜色")]public Color ChannelNameColor{get { return _channelNameColor; }set{_channelNameColor = value;Invalidate();}}[Category("外观")][Description("人数数字颜色")]public Color CountColor{get { return _countColor; }set{_countColor = value;Invalidate();}}[Category("外观")][Description("标签文本颜色")]public Color LabelColor{get { return _labelColor; }set{_labelColor = value;Invalidate();}}[Category("外观")][Description("控件背景颜色")]public Color BackgroundColor{get { return _backgroundColor; }set{_backgroundColor = value;Invalidate();}}[Category("外观")][Description("鼠标悬停颜色")]public Color HoverColor{get { return _hoverColor; }set{_hoverColor = value;Invalidate();}}[Category("外观")][Description("边框颜色")]public Color BorderColor{get { return _borderColor; }set{_borderColor = value;Invalidate();}}[Category("外观")][Description("通道名称字体")]public Font ChannelFont{get { return _channelFont; }set{_channelFont = value;Invalidate();}}[Category("外观")][Description("人数数字字体")]public Font CountFont{get { return _countFont; }set{_countFont = value;Invalidate();}}[Category("外观")][Description("标签文本字体")]public Font LabelFont{get { return _labelFont; }set{_labelFont = value;Invalidate();}}[Category("外观")][Description("边框圆角半径")]public int BorderRadius{get { return _borderRadius; }set{_borderRadius = Math.Max(0, value);Invalidate();}}[Category("外观")][Description("是否显示边框")]public bool ShowBorder{get { return _showBorder; }set{_showBorder = value;Invalidate();}}[Category("外观")][Description("标签文本(如'进场')")]public string LabelText{get { return _labelText; }set{_labelText = value;Invalidate();}}[Browsable(false)]public bool IsHovered{get { return _isHovered; }}#endregion#region 事件[Category("属性已更改")][Description("当进场人数发生变化时发生")]public event EventHandler EntryCountChanged;[Category("行为")][Description("鼠标悬停时发生")]public event EventHandler HoverChanged;#endregion#region 构造函数public HorizontalChannelControl(){InitializeComponent();SetStyle(ControlStyles.AllPaintingInWmPaint |ControlStyles.UserPaint |ControlStyles.DoubleBuffer |ControlStyles.ResizeRedraw |ControlStyles.SupportsTransparentBackColor |ControlStyles.UserMouse, true);// 设置默认大小this.Size = new Size(280, 40);// 添加事件this.MouseEnter += OnMouseEnter;this.MouseLeave += OnMouseLeave;this.Click += OnClick;// 设置默认背景色this.BackColor = Color.Transparent;}protected virtual void OnEntryCountChanged(EventArgs e){EntryCountChanged?.Invoke(this, e);}protected virtual void OnHoverChanged(EventArgs e){HoverChanged?.Invoke(this, e);}#endregion#region 鼠标事件private void OnMouseEnter(object sender, EventArgs e){_isHovered = true;OnHoverChanged(EventArgs.Empty);Invalidate();}private void OnMouseLeave(object sender, EventArgs e){_isHovered = false;OnHoverChanged(EventArgs.Empty);Invalidate();}private void OnClick(object sender, EventArgs e){OnClick(e);}#endregion#region 绘制方法protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);Graphics g = e.Graphics;g.SmoothingMode = SmoothingMode.AntiAlias;g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;// 绘制圆角背景DrawRoundedBackground(g);// 计算各区域宽度int channelNameWidth = (int)(Width * 0.4); // 40% 给通道名称int labelWidth = (int)(Width * 0.2); // 20% 给标签int countWidth = (int)(Width * 0.4); // 40% 给进场人数// 绘制通道名称DrawChannelName(g, new Rectangle(10, 0, channelNameWidth - 10, Height));// 绘制标签DrawLabel(g, new Rectangle(channelNameWidth, 0, labelWidth, Height));// 绘制进场人数DrawEntryCount(g, new Rectangle(channelNameWidth + labelWidth, 0, countWidth - 10, Height));}private void DrawRoundedBackground(Graphics g){Color bgColor = _isHovered ? _hoverColor : _backgroundColor;using (GraphicsPath path = CreateRoundedRectanglePath(ClientRectangle, _borderRadius))using (SolidBrush backgroundBrush = new SolidBrush(bgColor)){g.FillPath(backgroundBrush, path);}// 绘制边框if (_showBorder){using (GraphicsPath path = CreateRoundedRectanglePath(ClientRectangle, _borderRadius))using (Pen borderPen = new Pen(_borderColor, 1)){g.DrawPath(borderPen, path);}}}private GraphicsPath CreateRoundedRectanglePath(Rectangle rect, int radius){GraphicsPath path = new GraphicsPath();if (radius <= 0){path.AddRectangle(rect);return path;}int diameter = radius * 2;Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));// 左上角path.AddArc(arcRect, 180, 90);// 右上角arcRect.X = rect.Right - diameter;path.AddArc(arcRect, 270, 90);// 右下角arcRect.Y = rect.Bottom - diameter;path.AddArc(arcRect, 0, 90);// 左下角arcRect.X = rect.Left;path.AddArc(arcRect, 90, 90);path.CloseFigure();return path;}private void DrawChannelName(Graphics g, Rectangle rect){using (SolidBrush channelBrush = new SolidBrush(_channelNameColor)){StringFormat format = new StringFormat();format.LineAlignment = StringAlignment.Center;format.Alignment = StringAlignment.Near;g.DrawString(_channelName, _channelFont, channelBrush, rect, format);}}private void DrawLabel(Graphics g, Rectangle rect){using (SolidBrush labelBrush = new SolidBrush(_labelColor)){StringFormat format = new StringFormat();format.LineAlignment = StringAlignment.Center;format.Alignment = StringAlignment.Center;g.DrawString(_labelText, _labelFont, labelBrush, rect, format);}}private void DrawEntryCount(Graphics g, Rectangle rect){using (SolidBrush countBrush = new SolidBrush(_countColor)){StringFormat format = new StringFormat();format.LineAlignment = StringAlignment.Center;format.Alignment = StringAlignment.Center;g.DrawString(_entryCount.ToString(), _countFont, countBrush, rect, format);}}#endregion#region 公共方法/// <summary>/// 设置进场人数/// </summary>/// <param name="count">进场人数</param>public void SetEntryCount(int count){EntryCount = count;}/// <summary>/// 增加进场人数/// </summary>/// <param name="increment">增加的数量</param>public void IncrementEntryCount(int increment = 1){EntryCount += increment;}/// <summary>/// 重置进场人数/// </summary>public void ResetEntryCount(){EntryCount = 0;}/// <summary>/// 获取通道信息/// </summary>/// <returns>通道信息字符串</returns>public string GetChannelInfo(){return $"{_channelName}: {_entryCount}人{_labelText}";}/// <summary>/// 高亮显示控件/// </summary>public void Highlight(){_isHovered = true;Invalidate();}/// <summary>/// 取消高亮显示/// </summary>public void Unhighlight(){_isHovered = false;Invalidate();}/// <summary>/// 设置紧凑模式(更小的尺寸)/// </summary>public void SetCompactMode(){this.Size = new Size(140, 35);_channelFont = new Font("微软雅黑", 9, FontStyle.Bold);_countFont = new Font("微软雅黑"