笔记承接:承接多线程全套课程,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 防闪屏三行核心配置作用
-
UserPaint:开启用户自定义绘制权限,必须配合重写OnPaint
-
OptimizedDoubleBuffer:开启双缓存,内存绘图,根治刷新白屏
-
AllPaintingInWmPaint:屏蔽系统窗口刷新消息,消除系统自带闪烁
5.3 高清绘图四大配置
-
图层覆盖:SourceOver,新图层覆盖旧画布
-
高质量合成:优化图层成像画质
-
抗锯齿:消除线条、文字毛刺
-
高清插值:缩放控件保留绘图细节
5.4 Description特性作用
添加特性后,自定义属性展示在Visual Studio右侧属性面板,可以可视化修改控件参数,和系统内置控件效果一致
5.5 using包裹画笔作用
画笔、画布属于系统绘图资源,占用内存;using执行完毕自动释放资源,防止内存泄漏、程序卡顿