tx
2025-04-09 fa7510e1ed63df0366787fa4ed1b3db6426d2b46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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
    }
 
}