C# WinForm 自定义控件

笔记承接:承接多线程全套课程,WinForm进阶重难点;本节课讲解控件继承架构、三类自定义控件、GDI重绘、界面闪屏优化

考试核心:控件继承链路、三种自定义控件区别、双缓存防闪屏、自定义属性特性

工程结构:Form1主窗体 + UserControl1完全自定义控件

一、控件底层继承链路(必考选择题)

所有WinForm控件全部继承自顶层组件,自上而下继承关系

复制代码
//控件继承链路【背诵】
//Component 组件 ---> Control 控件基类 ---> ButtonBase按钮基类 ---> Button按钮

//两类特殊组件
//1.可视化控件:Button、Label、TextBox 全部继承Control
//2.非可视化组件:Timer、ImageList 直接继承Component,没有可视化界面

1.1 控件继承层级(必考)

控件继承链路:Component组件 → Control控件 → ButtonBase → Button按钮

补充:Timer计时器 直接继承 Component,不属于可视化控件

二、三种自定义控件方式(大题必考)

2.1 扩展控件(最简单)

  • 继承关系:继承系统已有控件,例如 Button、Label

  • 原理:在原有控件基础上拓展属性、事件,保留原生样式

  • 适用场景:原生按钮缺少颜色、状态属性,小幅拓展功能

2.2 用户控件(组合控件)

  • 继承关系:继承 UserControl

  • 原理:拖拽多个原生控件(按钮、文本框)拼装成全新控件

  • VS内置模板,不需要手写底层绘制,开发最快

  • 适用场景:页面复用模块、登录面板、导航栏

2.3 完全自定义控件(本节课案例)

  • 继承关系:手动修改继承,继承顶层基类 Control

  • 特点:无任何原生界面,全部界面手动GDI绘制

  • 报错修复:修改继承关系为Control后,窗体报错解决方案:注释掉构造函数自动生成代码:this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

  • 适用场景:异形控件、仪表盘、渐变按钮、自定义图表

三、前置难点:界面闪烁问题&双缓存原理

3.1 闪屏产生原因

控件刷新界面:先清空原有画布、再绘制新画面,清空瞬间出现空白白屏,反复刷新产生画面闪烁

3.2 双缓存原理(背诵)

不在界面直接绘图,先把全部图形、文字绘制到内存画布,绘制完毕后,一次性粘贴到窗体界面,消除清空画布空白期,彻底解决闪屏

3.3 三大样式配置(固定代码,必考默写)

复制代码
//开启用户自定义绘制、内存双缓存、屏蔽窗口闪烁消息
SetStyle(ControlStyles.UserPaint 
| ControlStyles.OptimizedDoubleBuffer 
| ControlStyles.AllPaintingInWmPaint, true);
UpdateStyles();//立即更新控件样式,生效配置
        }
  • UserPaint:开启手动绘制权限,允许重写OnPaint绘制界面

  • OptimizedDoubleBuffer:开启内存双缓存,优先绘制到内存

  • AllPaintingInWmPaint:屏蔽系统窗口刷新消息,规避系统自带闪屏

四、完全自定义控件逐行代码批注

4.1 命名空间规整

统一全部依赖,绘图必须引入Drawing2D空间,原生代码自动补齐

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//额外依赖:绘图命名空间(自动引入)
//using System.Drawing.Drawing2D;

片段3:完全自定义控件 UserControl1 完整代码

核心流程:修改继承→开启双缓存→重写绘制方法→自定义属性→文本居中绘制

复制代码
namespace _5自定义控件
{
    //三种自定义控件的方式
    //1、扩展控件 :继承于内置的控件 例如Button
    //2、用户控件: 继承于UserControl ,c#创建的时候有内置的模版,拖拽拼接控件
    //3、完全自定义控件 :继承于Control,手动改继承关系
    //改完继承关系会报错:注释掉 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

    //完全自定义控件步骤
    //1 继承于Control
    //2 重绘界面:重写父类的OnPaint绘制方法
    //3 防闪屏配置:开启双缓存,消除界面刷新白闪

    public partial class UserControl1 : Control
    {
        //自定义控件构造函数
        public UserControl1()
        {
            InitializeComponent();

            //========== 双缓存+自定义绘制样式配置【必考代码】 ==========
            //ControlStyles.UserPaint:允许用户手动绘制控件,必须重写OnPaint方法
            //ControlStyles.OptimizedDoubleBuffer:开启内存双缓存,先绘内存、再贴界面,减少闪烁
            //ControlStyles.AllPaintingInWmPaint:忽略窗口消息,屏蔽系统自带刷新闪烁
            SetStyle(ControlStyles.UserPaint | 
                     ControlStyles.OptimizedDoubleBuffer | 
                     ControlStyles.AllPaintingInWmPaint, true);

            UpdateStyles();//立即更新控件样式,生效配置
        }

4.2 构造函数:初始化+防闪屏

复制代码
        public UserControl1()
        {
            InitializeComponent();
            //三行固定防闪屏代码,自定义控件标配
            SetStyle(ControlStyles.UserPaint 
                | ControlStyles.OptimizedDoubleBuffer 
                | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
        }

4.3 重写绘制方法 OnPaint(核心)

OnPaint:控件绘制消息方法,控件刷新、加载、缩放自动触发,禁止手动调用

功能:画布配置、抗锯齿、高清绘图、绘制背景矩形、绘制居中文字

复制代码
        //重写父类绘制虚方法,所有绘图逻辑全部写在这里
        protected override void OnPaint(PaintEventArgs e)
        {
            //1.执行父类原有绘制逻辑,保留控件基础功能,必须写!
            base.OnPaint(e);

            //2.获取绘图画布:GDI绘图核心对象
            Graphics g = e.Graphics;

            //========画质优化四件套【默写考点】========
            g.CompositingMode = CompositingMode.SourceOver; 
            //绘制新图像覆盖原有画布,防止图层重叠错乱
            g.CompositingQuality = CompositingQuality.HighQuality; //合成高质量画质
            g.SmoothingMode = SmoothingMode.AntiAlias; //图像抗锯齿,消除毛刺
            g.InterpolationMode = InterpolationMode.HighQualityBilinear;
            //缩放保真,图片不失真
            //高清插补算法,控件缩放时,保留图像细节,保证画质

            //3.定义绘制矩形:边距5px,自适应控件宽高
            RectangleF rtf = new RectangleF(5, 5, this.Width - 10, this.Height - 10);

            //4.画笔资源:using自动释放GDI资源,防止内存泄漏
            using (SolidBrush txtBrush = new SolidBrush(Color.Red))//文字画笔
            using (SolidBrush backBrush = new SolidBrush(Color.Gray))//背景画笔
            {
                g.FillRectangle(backBrush, rtf);//绘制灰色背景矩形
                g.DrawString(MyTxt, font, txtBrush, rtf, Format);//居中绘制文本
            }
        }

4.4 全局字体对象

复制代码
        //全局字体:宋体、19号字号
        private Font font = new Font("宋体", 19);

4.5 自定义公开属性(设计器属性)

**Description**特性:VS右侧属性面板展示备注,可视化配置属性,期末考点

复制代码
        //自定义文本属性,面板可以直接修改
        [Description("文本内容")]//属性注释,展示在vs右侧属性栏
        public string MyTxt
        {
            get => Text;
            set => Text = value;
        }

4.6 文本排版样式属性

复制代码
       //全局字符串格式化对象
        private StringFormat format = null;

        //自定义字体样式属性
        [Description("设置字体样式")]
        public StringFormat Format
        {
            get
            {
                //懒加载:第一次调用初始化,避免重复创建对象
                if(format==null)
                {
                    format = new StringFormat();// 创建字符串格式化对象
                    format.Alignment = StringAlignment.Center; // 文本水平居中
                    format.LineAlignment = StringAlignment.Center; // 文本垂直居中
                    format.FormatFlags = StringFormatFlags.NoWrap;// 禁止文本自动换行
                    format.Trimming = StringTrimming.EllipsisCharacter; //文本超出控件范围,显示省略号
                }
                return format;
            }
           
        }

五、课堂必考简答题考点

5.1 三种自定义控件优缺点

  • 扩展控件:开发最快,只能修改原有控件样式,自由度低

  • 用户控件UserControl:拖拽拼接、上手简单,无法深度自定义绘图

  • 自定义Control控件:从零绘图、自由度最高,代码量大,需要处理闪屏

5.2 防闪屏三行核心配置作用

  1. UserPaint:开启用户自定义绘制权限,必须配合重写OnPaint

  2. OptimizedDoubleBuffer:开启双缓存,内存绘图,根治刷新白屏

  3. AllPaintingInWmPaint:屏蔽系统窗口刷新消息,消除系统自带闪烁

5.3 高清绘图四大配置

  • 图层覆盖:SourceOver,新图层覆盖旧画布

  • 高质量合成:优化图层成像画质

  • 抗锯齿:消除线条、文字毛刺

  • 高清插值:缩放控件保留绘图细节

5.4 Description特性作用

添加特性后,自定义属性展示在Visual Studio右侧属性面板,可以可视化修改控件参数,和系统内置控件效果一致

5.5 using包裹画笔作用

画笔、画布属于系统绘图资源,占用内存;using执行完毕自动释放资源,防止内存泄漏、程序卡顿

相关推荐
hsg779 小时前
简述:Rust、GeoRust、自主研发GIS平台
开发语言·后端·rust
承渊政道9 小时前
飞算Java炫技赛:Java×Unity数字孪生园区平台的从零落地记录
java·开发语言·unity·技术分享·vibe coding·飞算javaai·飞算java ai炫技赛
wdfk_prog15 小时前
嵌入式面试真题第 10 题:高优化等级下共享状态可见性、内存模型与系统级同步设计
java·linux·开发语言·面试·职场和发展·架构·c
许彰午18 小时前
95_Python内存管理与垃圾回收
开发语言·python
多加点辣也没关系19 小时前
JavaScript|第13章:原始类型的方法
开发语言·javascript·ecmascript
এ慕ོ冬℘゜19 小时前
深入理解 JavaScript 事件体系:Window、鼠标与键盘事件详解
开发语言·javascript·okhttp
chouchuang20 小时前
day-030-综合练习-笔记管理器
开发语言·笔记·python
云空21 小时前
《Three.js 3D实例大全》
开发语言·javascript·3d·three.js
techdashen21 小时前
Go 1.26 新增 `bytes.Buffer.Peek`:只看数据,不移动读取位置
开发语言·后端·golang
C137的本贾尼1 天前
第七篇:消息队列(MQ)——就是个带存储的异步通信管道
java·开发语言·中间件