Toggle Button(开关按钮)是一个常见的UI控件,用于表示两种状态之间的切换(开/关、是/否等)。本文将详细介绍如何在C#中实现一个自定义的Toggle Button控件。
Toggle Button(开关按钮)是一个常见的UI控件,用于表示两种状态之间的切换(开/关、是/否等)。本文将详细介绍如何在C#中实现一个自定义的Toggle Button控件。
我们的切换按钮具备以下关键特性:
SmoothingMode.AntiAlias
确保视觉质量首先,我们需要继承CheckBox
控件来创建我们的Toggle Button:
C#using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Timer = System.Windows.Forms.Timer;
namespace AppControls
{
public class ToggleButton : CheckBox
{
// 定义私有字段
private Color _onBackColor = Color.MediumSlateBlue;
private Color _onToggleColor = Color.WhiteSmoke;
private Color _offBackColor = Color.Gray;
private Color _offToggleColor = Color.Gainsboro;
// 当前开关状态
private bool _isOn = false;
private int _toggleSize;
public ToggleButton()
{
this.MinimumSize = new Size(45, 22);
// 设置控件样式
this.Cursor = Cursors.Hand;
// 启用双缓冲,减少闪烁
this.DoubleBuffered = true;
}
// 自定义属性
public Color OnBackColor
{
get => _onBackColor;
set
{
_onBackColor = value;
this.Invalidate();
}
}
public Color OnToggleColor
{
get => _onToggleColor;
set
{
_onToggleColor = value;
this.Invalidate();
}
}
public Color OffBackColor
{
get => _offBackColor;
set
{
_offBackColor = value;
this.Invalidate();
}
}
public Color OffToggleColor
{
get => _offToggleColor;
set
{
_offToggleColor = value;
this.Invalidate();
}
}
public virtual bool Checked
{
get => _isOn;
set
{
_isOn = value;
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
Graphics g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
pevent.Graphics.Clear(this.Parent.BackColor);
// 计算控件尺寸
int toggleSize = this.Height - 5;
_toggleSize = toggleSize;
// 创建绘图路径
using (GraphicsPath path = new GraphicsPath())
{
// 绘制背景
path.AddArc(0, 0, this.Height, this.Height, 90, 180);
path.AddArc(this.Width - this.Height, 0, this.Height, this.Height, 270, 180);
path.CloseFigure();
// 设置背景颜色
g.FillPath(new SolidBrush(_isOn ? _onBackColor : _offBackColor), path);
// 绘制开关按钮
float toggleLocation = _isOn ? this.Width - this.Height + 2 : 2;
g.FillEllipse(new SolidBrush(_isOn ? _onToggleColor : _offToggleColor),
toggleLocation, 2, toggleSize, toggleSize);
}
}
protected override void OnClick(EventArgs e)
{
this._isOn = !this._isOn;
base.OnClick(e);
this.Invalidate(); // 重绘控件
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
}
}
}
C#using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Timer = System.Windows.Forms.Timer;
namespace AppControls
{
public class ToggleButton : CheckBox
{
// 定义私有字段
private Color _onBackColor = Color.MediumSlateBlue;
private Color _onToggleColor = Color.WhiteSmoke;
private Color _offBackColor = Color.Gray;
private Color _offToggleColor = Color.Gainsboro;
private int _border = 1;
// 当前开关状态
private bool _isOn = false;
// 动画相关字段
private float _toggleLocation;
private readonly Timer _animationTimer;
private const int ANIMATION_SPEED = 4; // 动画速度
private int _toggleSize;
public ToggleButton()
{
this.MinimumSize = new Size(45, 22);
// 设置控件样式
this.Cursor = Cursors.Hand;
// 启用双缓冲,减少闪烁
this.DoubleBuffered = true;
// 初始化动画计时器
_animationTimer = new Timer();
_animationTimer.Interval = 1; // 1毫秒间隔
_animationTimer.Tick += AnimationTimer_Tick;
}
private void AnimationTimer_Tick(object sender, EventArgs e)
{
float targetLocation = _isOn ? this.Width - this.Height + 2 : 2;
// 计算动画步进
if (Math.Abs(_toggleLocation - targetLocation) > ANIMATION_SPEED)
{
_toggleLocation += _isOn ? ANIMATION_SPEED : -ANIMATION_SPEED;
this.Invalidate();
}
else
{
_toggleLocation = targetLocation;
_animationTimer.Stop();
this.Invalidate();
}
}
// 自定义属性
public Color OnBackColor
{
get => _onBackColor;
set
{
_onBackColor = value;
this.Invalidate();
}
}
public int Border
{
get { return _border; }
set
{
_border = value;
this.Invalidate();
}
}
public Color OnToggleColor
{
get => _onToggleColor;
set
{
_onToggleColor = value;
this.Invalidate();
}
}
public Color OffBackColor
{
get => _offBackColor;
set
{
_offBackColor = value;
this.Invalidate();
}
}
public Color OffToggleColor
{
get => _offToggleColor;
set
{
_offToggleColor = value;
this.Invalidate();
}
}
public virtual bool Checked
{
get => _isOn;
set
{
if (_isOn != value)
{
_isOn = value;
StartAnimation();
}
}
}
private void StartAnimation()
{
if (!_animationTimer.Enabled)
{
_animationTimer.Start();
}
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
Graphics g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
pevent.Graphics.Clear(this.Parent.BackColor);
// 计算控件尺寸
int toggleSize = this.Height - 5;
_toggleSize = toggleSize;
// 创建绘图路径
using (GraphicsPath path = new GraphicsPath())
{
// 绘制背景
int arcHeight = this.Height - 1;
Rectangle leftArc = new Rectangle(0, 0, arcHeight, arcHeight);
Rectangle rightArc = new Rectangle(this.Width - arcHeight - 2, 0, arcHeight, arcHeight);
path.StartFigure();
path.AddArc(leftArc, 90, 180);
path.AddArc(rightArc, 270, 180);
path.CloseFigure();
if (Border > 0)
{
pevent.Graphics.DrawPath(new Pen(_onBackColor, Border), path);
}
else
{
// 设置背景颜色
g.FillPath(new SolidBrush(_isOn ? _onBackColor : _offBackColor), path);
}
// 绘制开关按钮
g.FillEllipse(new SolidBrush(_isOn ? _onToggleColor : _offToggleColor),
_toggleLocation, 2, toggleSize, toggleSize);
}
}
protected override void OnClick(EventArgs e)
{
_isOn = !_isOn;
StartAnimation();
base.OnClick(e);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
_toggleLocation = _isOn ? this.Width - this.Height + 2 : 2;
}
// 确保在控件销毁时停止并清理计时器
protected override void Dispose(bool disposing)
{
if (disposing)
{
_animationTimer.Stop();
_animationTimer.Dispose();
}
base.Dispose(disposing);
}
}
}
通过以上步骤,我们实现了一个功能完整的Toggle Button控件。这个控件不仅支持自定义外观(如颜色和大小的调整),还具备流畅的动画效果和良好的性能优化。同时,它拥有完整的事件处理机制,并采用了可扩展的设计理念。在实际应用中,可以根据具体需求对控件进行进一步的定制和优化,以满足不同的使用场景。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!