一、本案例包含两大核心知识点

  1. 扩展式自定义控件:继承原生 TextBox,拓展自定义属性

  2. 自定义可视化组件(Component):继承 Component,封装属于自己的 Timer 定时器(无界面组件)

二、拓展控件:继承 TextBox(有界面控件扩展)

1. 原理

继承系统原生 TextBox,保留原有所有输入、样式功能,仅拓展自定义属性,属于最简单的自定义控件方式。

2. 核心技术点

  • [Description("说明")]:特性标记,让属性在VS属性窗口显示中文注释

  • Refresh():赋值后强制刷新界面,让属性修改立即生效

3. 完整代码

namespace _1自定义控件
{
    // 扩展原生TextBox控件
    public partial class UserControl1 : TextBox
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        // 自定义拓展属性:自定义背景色
        [Description("背景颜色")]
        public Color MyColor
        {
            get
            {
                return BackColor;
            }
            set
            {
                BackColor = value;
                Refresh(); // 修改后立即刷新界面生效
            }
        }
    }
}

三、自定义组件:继承 Component 封装 Timer 定时器

1. 核心概念(必考)

  • 控件(Control):有界面、可拖拽、可见元素(Button/TextBox)

  • 组件(Component):无界面、后台运行、不可见元素(Timer/MessageBox)

本案例:手动封装一个属于自己的定时器组件,自带事件、开关、间隔属性。

2. 三种定时器区别(必背)

  • System.Timers.Timer:基于线程池,后台触发,子线程触发事件

  • System.Windows.Forms.Timer:基于UI消息循环,主线程触发,无需Invoke

  • System.Threading.Timer:基于线程,精度高、使用复杂

本案例使用:System.Timers.Timer

3. 核心功能实现

  • 自定义 myTick 事件:对外暴露定时器触发事件,供窗体绑定

  • 封装 TimerInterval 间隔属性

  • 封装 TimerEnabled 启停属性

  • 双重构造函数:默认构造 + 容器构造(适配组件托管)

4. 完整自定义Timer组件代码

using System;
using System.ComponentModel;
using System.Timers;

namespace _1自定义控件
{
    // 继承Component:无界面自定义组件
    public partial class UserControl2 : Component
    {
        // 系统定时器对象
        public Timer _timer = new Timer();

        // 自定义定时器触发事件(对外暴露)
        public event EventHandler myTick;

        // 默认构造函数
        public UserControl2()
        {
            InitializeComponent();
            _timer = new Timer(TimerInterval);
            // 绑定定时器触发事件
            _timer.Elapsed += _timer_Elapsed;
        }

        // 容器构造函数(组件托管必备)
        public UserControl2(IContainer c)
        {
            c.Add(this);
            InitializeComponent();
            _timer = new Timer(TimerInterval);
            _timer.Elapsed += _timer_Elapsed;
        }

        // 定时器触发回调
        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // 有订阅者才触发,避免空报错
            myTick?.Invoke(sender, e);
        }

        // 自定义属性:定时器间隔
        [Description("定时器间隔")]
        public double TimerInterval
        {
            get
            {
                return _timer.Interval;
            }
            set
            {
                _timer.Interval = value;
            }
        }

        // 自定义属性:定时器启停开关
        [Description("定时器是否启用")]
        public bool TimerEnabled
        {
            get
            {
                return _timer.Enabled;
            }
            set
            {
                _timer.Enabled = value;
            }
        }
    }
}

四、窗体调用测试代码

实现:开启定时器、关闭定时器、触发自定义事件打印内容

namespace _1自定义控件
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 自定义定时器触发事件
        private void userControl21_myTick(object sender, EventArgs e)
        {
            Console.WriteLine("1111");
        }

        // 开启定时器
        private void button1_Click(object sender, EventArgs e)
        {
            userControl21.TimerEnabled = true;
        }

        // 关闭定时器
        private void button2_Click(object sender, EventArgs e)
        {
            userControl21.TimerEnabled = false;
        }
    }
}

五、核心考点与注意事项

  • 扩展控件:继承原生控件,复用原有功能,只拓展属性/方法,开发最简单

  • 组件与控件区别:Control可见可拖拽,Component无界面后台运行

  • 自定义事件写法public event EventHandler 事件名,通过 ?.Invoke 安全触发

  • 属性特性[Description] 让自定义属性在属性窗口显示中文说明

  • 刷新机制:拓展属性赋值后调用 Refresh(),UI立即更新

  • Timer组件线程问题:Timers.Timer 事件在子线程触发,更新UI必须使用 Invoke

  • 双构造函数:自定义Component必须包含无参、带容器参数构造,保证组件正常托管

六、三类自定义控件终极总结

  1. 扩展控件:继承 Button/TextBox,拓展属性(本次案例1)

  2. 用户控件:继承 UserControl,组合多个控件

  3. 完全自定义控件/组件:继承 Control(有界面)/ Component(无界面)(本次案例2)

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐