C# 中实现自定义按钮控件,用于替代 WinForms 默认按钮,实现个性化样式(如圆角、渐变、悬停 / 点击效果)并保证高可复用性,本文将提供完整的实现方案,包括自定义控件核心代码、使用方法及扩展特性。一、核心思路
自定义按钮的核心是继承Button基类(复用按钮原有交互逻辑,如点击事件、焦点状态等),通过重写OnPaint方法实现个性化绘制,同时暴露可自定义属性(圆角、颜色、渐变等),支持设计时编辑和运行时动态修改,满足不同 UI 风格需求。
二、完整实现代码
1. 自定义按钮控件(CustomStyleButton.cs)
using System;using System.Drawing;using System.Drawing.Drawing2D;using System.Windows.Forms;using System.ComponentModel;namespace CustomControls{ public class CustomStyleButton : Button { #region 私有字段 private int _cornerRadius = 10; private Color _gradientStartColor = Color.LightSkyBlue; private Color _gradientEndColor = Color.RoyalBlue; private Color _hoverStartColor = Color.LightBlue; private Color _hoverEndColor = Color.DodgerBlue; private Color _pressedStartColor = Color.SkyBlue; private Color _pressedEndColor = Color.Blue; private Color _buttonTextColor = Color.White; #endregion #region 公共属性(支持设计时编辑) [Description("按钮圆角半径(值越大圆角越明显)"), Category("自定义按钮样式")] public int CornerRadius { get => _cornerRadius; set { _cornerRadius = Math.Max(0, value); Invalidate(); } } [Description("正常状态下渐变起始颜色"), Category("自定义按钮样式")] public Color GradientStartColor { get => _gradientStartColor; set { _gradientStartColor = value; Invalidate(); } } [Description("正常状态下渐变结束颜色"), Category("自定义按钮样式")] public Color GradientEndColor { get => _gradientEndColor; set { _gradientEndColor = value; Invalidate(); } } [Description("鼠标悬停时渐变起始颜色"), Category("自定义按钮样式")] public Color HoverStartColor { get => _hoverStartColor; set { _hoverStartColor = value; Invalidate(); } } [Description("鼠标悬停时渐变结束颜色"), Category("自定义按钮样式")] public Color HoverEndColor { get => _hoverEndColor; set { _hoverEndColor = value; Invalidate(); } } [Description("鼠标点击时渐变起始颜色"), Category("自定义按钮样式")] public Color PressedStartColor { get => _pressedStartColor; set { _pressedStartColor = value; Invalidate(); } } [Description("鼠标点击时渐变结束颜色"), Category("自定义按钮样式")] public Color PressedEndColor { get => _pressedEndColor; set { _pressedEndColor = value; Invalidate(); } } [Description("按钮显示文字的颜色"), Category("自定义按钮样式")] public Color ButtonTextColor { get => _buttonTextColor; set { _buttonTextColor = value; Invalidate(); } } #endregion #region 构造函数 public CustomStyleButton() { this.FlatStyle = FlatStyle.Flat; this.FlatAppearance.BorderSize = 0; this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true); this.DoubleBuffered = true; this.Font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point); } #endregion #region 核心重写方法:OnPaint(绘制自定义按钮样式) protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; Rectangle buttonRect = new Rectangle(0, 0, this.Width - 1, this.Height - 1); using (GraphicsPath buttonPath = new GraphicsPath()) { buttonPath.AddArc(buttonRect.X, buttonRect.Y, _cornerRadius, _cornerRadius, 180, 90); buttonPath.AddArc(buttonRect.Right - _cornerRadius, buttonRect.Y, _cornerRadius, _cornerRadius, 270, 90); buttonPath.AddArc(buttonRect.Right - _cornerRadius, buttonRect.Bottom - _cornerRadius, _cornerRadius, _cornerRadius, 0, 90); buttonPath.AddArc(buttonRect.X, buttonRect.Bottom - _cornerRadius, _cornerRadius, _cornerRadius, 90, 90); buttonPath.CloseAllFigures(); LinearGradientBrush gradientBrush = null; if (this.ClientRectangle.Contains(this.PointToClient(Cursor.Position)) && this.MouseButtons == MouseButtons.Left) { gradientBrush = new LinearGradientBrush(buttonRect, _pressedStartColor, _pressedEndColor, LinearGradientMode.Vertical); } else if (this.ClientRectangle.Contains(this.PointToClient(Cursor.Position))) { gradientBrush = new LinearGradientBrush(buttonRect, _hoverStartColor, _hoverEndColor, LinearGradientMode.Vertical); } else { gradientBrush = new LinearGradientBrush(buttonRect, _gradientStartColor, _gradientEndColor, LinearGradientMode.Vertical); } using (gradientBrush) { g.FillPath(gradientBrush, buttonPath); } using (Pen borderPen = new Pen(Color.FromArgb(50, Color.Black), 1)) { g.DrawPath(borderPen, buttonPath); } using (SolidBrush textBrush = new SolidBrush(_buttonTextColor)) { StringFormat stringFormat = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; g.DrawString(this.Text, this.Font, textBrush, buttonRect, stringFormat); } } } #endregion }}
三、控件使用方法
步骤 1:添加控件到窗体
- 将上述代码编译为类库(或直接放在 WinForms 项目中)
- 在 Visual Studio 工具箱中,右键→「选择项」→「浏览」→ 选中编译后的程序集,确认后
CustomStyleButton会出现在工具箱中 - 直接拖拽
CustomStyleButton到 WinForms 窗体上,可自由调整按钮大小
步骤 2:使用方式(设计时 + 运行时)
1. 设计时配置(可视化操作)
选中窗体上的CustomStyleButton,在「属性」窗口中找到「自定义按钮样式」分类,可直接修改:
2. 运行时动态修改(代码控制)
using System;using System.Drawing;using System.Windows.Forms;using CustomControls;namespace CustomButtonDemo{ public partial class FrmMain : Form { public FrmMain() { InitializeComponent(); } private void btnSetStyle_Click(object sender, EventArgs e) { customStyleButton1.CornerRadius = 20; customStyleButton1.GradientStartColor = Color.LightCoral; customStyleButton1.GradientEndColor = Color.DarkRed; customStyleButton1.ButtonTextColor = Color.Yellow; } private void btnSetText_Click(object sender, EventArgs e) { customStyleButton1.Text = "动态修改的按钮文字"; } private void customStyleButton1_Click(object sender, EventArgs e) { MessageBox.Show("自定义按钮被点击了!"); } }}
四、关键特性说明
- 核心继承:直接继承
System.Windows.Forms.Button,完全复用默认按钮的所有交互逻辑(点击事件、焦点、禁用状态等),无需额外封装事件 - 个性化样式
- 圆角效果:通过
GraphicsPath绘制圆角矩形,圆角半径可自定义 - 渐变背景:支持垂直渐变,正常 / 悬停 / 点击三种状态分别对应独立渐变颜色
- 状态切换:自动识别鼠标「正常」「悬停」「点击」三种状态,自动切换样式,无需手动处理鼠标事件
- 设计时支持:通过
[Description]和[Category]特性,属性可在 VS 属性窗口中分类显示,可视化配置更便捷 - 无闪烁:开启双缓冲和优化绘制样式,避免控件重绘时出现闪烁问题
- 高可复用性:一次封装,可在多个项目中拖拽使用,支持动态修改样式
阅读原文:原文链接
该文章在 2026/1/19 10:36:54 编辑过