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;
|
}
|
|
/// <summary>
|
/// 引发CheckedChanged事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
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
|
}
|
|
}
|