using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace WinCustControls { [DefaultEvent("CheckedChanged")] public partial class USwitch : UserControl { public USwitch() { InitializeComponent(); SetStyle(ControlStyles.Selectable, true);//控件可以接收焦点 SetStyle(ControlStyles.AllPaintingInWmPaint, true);//忽略窗口消息,减少闪烁 SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//绘制到缓冲区,减少闪烁 SetStyle(ControlStyles.UserPaint, true);//控件由其自身而不是操作系统绘制 SetStyle(ControlStyles.ResizeRedraw, true);//控件调整其大小时重绘 SetStyle(ControlStyles.SupportsTransparentBackColor, true);//支持透明背景 MouseDown += USwitch_MouseDown; } /// /// 引发CheckedChanged事件 /// /// /// private void USwitch_MouseDown(object sender, MouseEventArgs e) { CheckedChanged?.Invoke(this, new EventArgs()); } [Description("开关状态值改变时触发")] public event EventHandler CheckedChanged; private Color trueColor = Color.DarkTurquoise; [DefaultValue(typeof(Color), "DarkTurquoise"), Description("状态Checked为True时的背景色")] public Color TrueColor { get { return trueColor; } set { trueColor = value; Invalidate(); } } private Color falseColor = Color.Gray; [DefaultValue(typeof(Color), "Gray"), Description("状态Checked为False时的背景色")] public Color FalseColor { get { return falseColor; } set { falseColor = value; Invalidate(); } } private bool mChecked = false; [DefaultValue(typeof(bool), "False"), Description("开关状态值")] public bool Checked { get { return mChecked; } set { mChecked = value; Invalidate(); } } private string[] texts; [Description("开关两种状态的文本,必须是长度为2的字符串数组")] public string[] Texts { get { return texts; } set { texts = value; Invalidate(); } } private SwitchType switchType = SwitchType.Ellipse; [DefaultValue(typeof(SwitchType), "Ellipse"), Description("开关样式")] public SwitchType SwitchType { get { return switchType; } set { switchType = value; Invalidate(); } } public override Font Font { get => base.Font; set { base.Font = value; Invalidate(); } } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; //背景填充色 var fillColor = mChecked ? trueColor : falseColor; //外观形状的路径 GraphicsPath path = new GraphicsPath(); if (switchType == SwitchType.Ellipse) { //上边直线 path.AddLine(Height / 2, 1, Width - Height / 2, 1); //右边半圆弧 path.AddArc(Width - Height - 1, 1, Height - 2, Height - 2, -90, 180); //下边直线 右----左 path.AddLine(Width - Height / 2, Height - 1, Height / 2, Height - 1); //左边半圆弧 path.AddArc(1, 1, Height - 2, Height - 2, 90, 180); g.FillPath(new SolidBrush(fillColor), path); //开关的文本 string strText = ""; if (texts != null && texts.Length == 2) { if (mChecked) strText = texts[0]; else strText = texts[1]; } if (mChecked) { //填充右边正圆 直径 Height-2-4 g.FillEllipse(Brushes.White, new Rectangle(Width - Height - 1 + 2, 1 + 2, Height - 2 - 4, Height - 2 - 4)); if (string.IsNullOrEmpty(strText))//没有文本 { //左边就画一个小圆,边框为白色 直径 :右边圆的一半 g.DrawEllipse(new Pen(Color.White, 2), new Rectangle((Height - 2 - 4) / 2 - ((Height - 2 - 4) / 4), (Height - 2 - (Height - 2 - 4) / 2) / 2 + 1, (Height - 2 - 4) / 2, (Height - 2 - 4) / 2)); } else { //获取文本尺寸 SizeF sizeF = g.MeasureString(strText.Replace(" ", "A"), Font); //计算文本绘制的位置的矩形的左上角y坐标值 int textY = (Height - (int)sizeF.Height) / 2 + 2; //x坐标 1/2半径处 g.DrawString(strText, Font, Brushes.White, new Point((Height - 2 - 4) / 2, textY)); } } else //Checked 为False { //填充左边正圆 g.FillEllipse(Brushes.White, new Rectangle(1 + 2, 1 + 2, this.Height - 2 - 4, this.Height - 2 - 4)); if (string.IsNullOrEmpty(strText))//没有文本 { //右边就画一个小圆,边框为白色 直径 :左边圆的一半 g.DrawEllipse(new Pen(Color.White, 2), new Rectangle(this.Width - 2 - (this.Height - 2 - 4) / 2 - ((this.Height - 2 - 4) / 2) / 2, (this.Height - 2 - (this.Height - 2 - 4) / 2) / 2 + 1, (this.Height - 2 - 4) / 2, (this.Height - 2 - 4) / 2)); } else { //获取文本尺寸 SizeF sizeF = g.MeasureString(strText.Replace(" ", "A"), Font); //计算文本绘制的位置的矩形的左上角y坐标值 int textY = (Height - (int)sizeF.Height) / 2 + 2; //x坐标 1/2半径 g.DrawString(strText, Font, Brushes.White, new Point(this.Width - 2 - this.Height / 2 - ((int)sizeF.Width) + 4, textY)); } } } else if (switchType == SwitchType.Quadriateral)//四边形 { //圆角正方形边长 int intRadius = 5; //左上角圆弧 path.AddArc(0, 0, intRadius, intRadius, 180f, 90f); //右上角圆弧 path.AddArc(this.Width - intRadius - 1, 0, intRadius, intRadius, 270f, 90f); //右下角圆弧 path.AddArc(this.Width - intRadius - 1, this.Height - intRadius - 1, intRadius, intRadius, 0f, 90f); //左下角圆弧 path.AddArc(0, this.Height - intRadius - 1, intRadius, intRadius, 90f, 90f); //填充圆角矩形 g.FillPath(new SolidBrush(fillColor), path); //获取文本 string strText = string.Empty; if (texts != null && texts.Length == 2) { if (mChecked) { strText = texts[0]; } else { strText = texts[1]; } } if (mChecked) { //右边正方形圆角 GraphicsPath path2 = new GraphicsPath(); //左上角圆弧 path2.AddArc(this.Width - this.Height - 1 + 2, 1 + 2, intRadius, intRadius, 180f, 90f); //右上角圆弧 path2.AddArc(this.Width - 1 - 2 - intRadius, 1 + 2, intRadius, intRadius, 270f, 90f); //右下角圆弧 path2.AddArc(this.Width - 1 - 2 - intRadius, this.Height - 2 - intRadius - 1, intRadius, intRadius, 0f, 90f); //右下角圆弧 path2.AddArc(this.Width - this.Height - 1 + 2, this.Height - 2 - intRadius - 1, intRadius, intRadius, 90f, 90f); //填充圆角正方形 g.FillPath(Brushes.White, path2); if (string.IsNullOrEmpty(strText)) { //左边画个小圆 //小圆所在矩形左上角坐标 :x 1/2边长-1/2小圆半径 //y: 1/2边长-1/2小圆半径+1 //半径:1/2 正方形边长 g.DrawEllipse(new Pen(Color.White, 2), new Rectangle((this.Height - 2 - 4) / 2 - ((this.Height - 2 - 4) / 2) / 2, (this.Height - 2 - (this.Height - 2 - 4) / 2) / 2 + 1, (this.Height - 2 - 4) / 2, (this.Height - 2 - 4) / 2)); } else { //画文本 System.Drawing.SizeF sizeF = g.MeasureString(strText.Replace(" ", "A"), Font); //y坐标 int intTextY = (this.Height - (int)sizeF.Height) / 2 + 2; //x:1/2边长处 g.DrawString(strText, Font, Brushes.White, new Point((this.Height - 2 - 4) / 2, intTextY)); } } else//画关的外观 { //圆角正方形路径 左边 GraphicsPath path2 = new GraphicsPath(); path2.AddArc(1 + 2, 1 + 2, intRadius, intRadius, 180f, 90f); path2.AddArc(this.Height - 2 - intRadius, 1 + 2, intRadius, intRadius, 270f, 90f); path2.AddArc(this.Height - 2 - intRadius, this.Height - 2 - intRadius - 1, intRadius, intRadius, 0f, 90f); path2.AddArc(1 + 2, this.Height - 2 - intRadius - 1, intRadius, intRadius, 90f, 90f); //填充圆角正方形 g.FillPath(Brushes.White, path2); if (string.IsNullOrEmpty(strText)) { //无文本,画右边小圆 //小圆所在矩形左上角坐标 :x 宽度-2-1/2边长-1/2小圆半径 //y: 1/2边长-1/2小圆半径+1 //半径:1/2 正方形边长 g.DrawEllipse(new Pen(Color.White, 2), new Rectangle(this.Width - 2 - (this.Height - 2 - 4) / 2 - ((this.Height - 2 - 4) / 2) / 2, (this.Height - 2 - (this.Height - 2 - 4) / 2) / 2 + 1, (this.Height - 2 - 4) / 2, (this.Height - 2 - 4) / 2)); } else { //画文本 System.Drawing.SizeF sizeF = g.MeasureString(strText.Replace(" ", "A"), Font); //y坐标 int intTextY = (this.Height - (int)sizeF.Height) / 2 + 2; //x坐标 宽-2-1/2正方形边长-文字宽度+4 g.DrawString(strText, Font, Brushes.White, new Point(this.Width - 2 - (this.Height - 2 - 4) / 2 - (int)sizeF.Width + 4, intTextY)); } } } else //线型 { //线高 int intLineHeight = (this.Height - 2 - 4) / 2; // 上边直线 点 :高度,(高度-线高)/2 点:宽-高/2, (高度-线高)/2 path.AddLine(new Point(this.Height / 2, (this.Height - intLineHeight) / 2), new Point(this.Width - this.Height / 2, (this.Height - intLineHeight) / 2)); //右边半圆弧 半径是 1/2线高 path.AddArc(new Rectangle(this.Width - this.Height / 2 - intLineHeight - 1, (this.Height - intLineHeight) / 2, intLineHeight, intLineHeight), -90, 180); //下边直线 path.AddLine(new Point(this.Width - this.Height / 2, (this.Height - intLineHeight) / 2 + intLineHeight), new Point(this.Width - this.Height / 2, (this.Height - intLineHeight) / 2 + intLineHeight)); //左边半圆弧 path.AddArc(new Rectangle(this.Height / 2, (this.Height - intLineHeight) / 2, intLineHeight, intLineHeight), 90, 180); //填充线 g.FillPath(new SolidBrush(fillColor), path); if (mChecked)//绘制开时的外观 { //填充右边外圆 g.FillEllipse(new SolidBrush(fillColor), new Rectangle(this.Width - this.Height - 1 + 2, 1 + 2, this.Height - 2 - 4, this.Height - 2 - 4)); //填充右边内圆 //x坐标:宽-2-1/2外圆半径-1/2内圆半径-4 y坐标:高-2-1/2内圆半径+1 //内圆直径:(this.Height - 2 - 4) / 2 (高-2-4)/2 g.FillEllipse(Brushes.White, new Rectangle(this.Width - 2 - (this.Height - 2 - 4) / 2 - ((this.Height - 2 - 4) / 2) / 2 - 4, (this.Height - 2 - (this.Height - 2 - 4) / 2) / 2 + 1, (this.Height - 2 - 4) / 2, (this.Height - 2 - 4) / 2)); } else //关时的外观 { //填充左边外圆 g.FillEllipse(new SolidBrush(fillColor), new Rectangle(1 + 2, 1 + 2, this.Height - 2 - 4, this.Height - 2 - 4)); //填充左贺内圆 //x坐标:1/2外圆半径-1/2内圆半径+4 y坐标:1/2外圆半径-1/2内圆半径+1 //内圆直径:(this.Height - 2 - 4) / 2 (高-2-4)/2 g.FillEllipse(Brushes.White, new Rectangle((this.Height - 2 - 4) / 2 - ((this.Height - 2 - 4) / 2) / 2 + 4, (this.Height - 2 - (this.Height - 2 - 4) / 2) / 2 + 1, (this.Height - 2 - 4) / 2, (this.Height - 2 - 4) / 2)); } } } } public enum SwitchType { //圆形 Ellipse, //四边形 Quadriateral, //线形 Line } }