C#自定义控件

1。C#中控件和组件的区别:

一般组件派生于:Component类,所以从此类派生出的称之为组件。
一般用户控件派生于:Control类或UserControl类,所以从该类派生出的称之为用户控件。
他们之间的关系主要是:UserControl继承Control继承Component。

概括:组件包括控件,控件肯定是组件,但组件不一定是控件。

控件的突出特点:就是交互式组件(能动,能和客户交互),而用户控件则是将某些特定的组件或控件复合从而实现特定的业务功能。
https://blog.csdn.net/cxu123321/article/details/103014278

2。自定义控件分类?

自定义控件、扩展控件、复合控件
完全自定义控件: 继承Control类
扩展控件:继承某个具体的控件类,如:Button,Label等
复合控件:继承UserControl类,又称用户控件UserControl。即:把多个控件通过组合的形式,形成更大,功能更全的控件。

https://www.cnblogs.com/zhangchenliang/archive/2012/08/17/2643744.html
https://blog.csdn.net/yysyangyangyangshan/article/details/7078471

继承链

  • Button具体控件类
    继承链:Button—>ButtonBase—>Control—>Component

  • Control类
    继承链:Control—>Component

  • UserControl类
    继承链:UserControl—>ContainerControl—>ScrollableControl—>Control—>Component
    ContainerControl容器控件,支持其他控件向本控件中拖放。
    ScrollableControl滚动控件,让控件支持水平和垂直滚动条。

  • Component类

    C# Winform窗体中包括组件和控件两类:
    组件的基类是Component类
    控件的基类是Control类
    结论:控件肯定是组件,但组件不一定是控件

    控件包含两种:自定义控件、官方控件
    自定义控件包含三种:
    完全自定义的控件:直接继承Control类
    扩展控件:直接继承某一个官方控件,比如:Button,Label等
    用户控件:最常用一种自定义控件,也是最简单的,直接继承UserControl类

用户控件

概念:

用户控件:即UserControl,也称复合控件,又称组合控件,不能直接运行。必须嵌套在窗体中使用。
用户控件继承UserControl类,而UserControl—>…—>继承Control类

用户控件怎么创建?怎么设计?怎么使用?

创建:右键项目—>用户控件
在这里插入图片描述
设计:像窗体一样去设计。
使用:先编译,编译后工具箱发生变化,像使用自带的控件一样去使用用户控件。
建议:用户控件不建议在使用时编写业务逻辑,应该把业务逻辑写到用户控件中。优缺点:很容易编写逻辑,但不灵活。把用户控件的逻辑暴露出去,让开发者在使用此控件时,定制逻辑。优缺点:逻辑难写,但灵活。
公开属性和公共事件把握一个适度原则,切记:不要把用户控件中的某个具体的官方控件直接公开。

// 一般情况下在用户控件中最常用公开的:属性和事件。
public partial class Login : UserControl
{// 公开一个事件,考虑:这个事件什么时候触发?[Description("登录事件")]public event EventHandler LoginEvent;public Login(){InitializeComponent();// 用户控件,开发者不需要重绘,所以一般可以省略这些配置。/*this.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);*/}private void Login_Load(object sender, EventArgs e){}// 用户控件:公开属性//[Category("我的属性")]//[Category("杂项")]//[Category()][Category][DefaultValue(typeof(string), "账号:")]  // DefaultValue//[Obsolete]// 以上的特性都可以不用,如下的特性在自定义控件时,常用[Description("账号的标题,默认值账号:")]  // 主要提示用的[Browsable(true)]  // 控制某个公开属性是否可以在属性窗口中被开发者看见。使用时只能通过代码访问。public string AccountText{get { return this.lblAccount.Text; }set{if (string.IsNullOrWhiteSpace(value))throw new ArgumentNullException("AccountText属性不能为空!");if (value.Length != 3)throw new ArgumentNullException("AccountText属性只能输入3个汉字或字母!");this.lblAccount.Text = value;}}[Description("账号")]public string Account{get { return this.txtAccount.Text; }set{this.txtAccount.Text = value;}}[Description("密码")]public string Password{get { return this.txtPassword.Text; }set{this.txtPassword.Text = value;}}// LoginEvent的触发时机:让用户点击btnLogin按钮时,触发LoginEvent事件。private void btnLogin_Click(object sender, EventArgs e){//if (LoginEvent != null)//    LoginEvent.Invoke(sender, e);// 简写LoginEvent?.Invoke(sender, e);}
}

扩展控件

扩展控件怎么创建?怎么设计?怎么使用?

创建:两种方法,通过用户控件和组件修改而来。
设计:不建议使用设计器,建议直接编写代码。(难点)
使用:先编译,编译后工具箱发生变化,像使用自带的控件一样去使用扩展控件。
设计步骤:
a. 先公开扩展属性,事件等
b.在扩展控件类中,使用相应的属性实现具体的业务逻辑流。(重点:重写OnPaint事件!)

// 把一个用户控件改写成扩展控件,只需要把UserControl基类,改写成具体的控件类即可!
// 通过用户控件改写后,把错误修复一下即可。
// InitializeComponent()中的this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;去掉即可!

 public partial class MyTextBox : TextBox{public MyTextBox(){InitializeComponent();}[Description("文本框的背景,使用方式同BackColor")]public Color MyBackColor{get{return this.BackColor;}set{this.BackColor = value;Refresh();}}}

3。特性简单理解?

CategoryAttribute DescriptionAttribute
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、属性、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

特性是运行时给各种元素添加声明性标签。语法:[某个特性]

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
https://www.toutiao.com/article/6969542149637833230
https://www.toutiao.com/article/7106017793186824744

完全自定义控件

完全自定义控件继承Control,不是继承UserControl,VS2022中没有提供定义完全自定义控件的模板。
1.方法1:通过用户控件,改写成完全自定义控件。
2.方法2:通过组件,改写成完全自定义控件。

通过用户控件改写后,把错误修复一下即可。
InitializeComponent()中的this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;去掉即可!

    public partial class MyLabel : Control{// 私有字段,画图时使用private Font font = new Font("宋体", 9, FontStyle.Regular, GraphicsUnit.Point);public MyLabel(){InitializeComponent();// ControlStyles枚举项逐个设置,解决重绘时闪烁的问题/* this.SetStyle(ControlStyles.UserPaint, true);//自绘this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); //双缓冲,为了兼容this.SetStyle(ControlStyles.DoubleBuffer, true);// 双缓冲,主要解决闪烁的问题this.SetStyle(ControlStyles.ResizeRedraw, true); //调整大小时重绘this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); //禁止檫除背景this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); //透明效果*/// 简写:把ControlStyles多个枚举项都设置成truethis.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);this.BackColor = ColorTranslator.FromHtml("#ECE9D8");this.MouseEnter += MyLabel_MouseEnter;this.MouseLeave += MyLabel_MouseLeave;}private void MyLabel_MouseLeave(object sender, EventArgs e){this.TextColor = Color.FromArgb(22, 95, 162);this.Cursor = Cursors.Arrow;font = new Font("宋体", 9, FontStyle.Regular, GraphicsUnit.Point);Refresh();}private void MyLabel_MouseEnter(object sender, EventArgs e){this.TextColor = Color.Red;this.Cursor = Cursors.Hand;font = new Font("宋体", 12, FontStyle.Bold | FontStyle.Italic, GraphicsUnit.Point);Refresh();}/// <summary>/// 对画布配置,让画面画出来的图形更清晰,质量更高/// </summary>/// <param name="g">画布</param>private void SetGraphics(Graphics g){// 设置合成模式为源覆盖g.CompositingMode = CompositingMode.SourceOver;// 合成图像时,使用高质量模式g.CompositingQuality = CompositingQuality.HighQuality;// 抗锯齿(让画笔,画刷平滑些,更清晰)g.SmoothingMode = SmoothingMode.AntiAlias;// 设置插值模式为高质量双三次插值g.InterpolationMode = InterpolationMode.HighQualityBicubic;}// 完全自定义的控件要求:// 1。必须继承Control类。// 2。需要重绘(你自己画控件),需要重写一个方法OnPaint()// 3。考虑闪屏(双缓冲),固定配置protected override void OnPaint(PaintEventArgs e){base.OnPaint(e); // 调用基类OnPaint,可以省略。也可以留下。留下时建议写到第一行。// 如何画图?使用GDI或GDI+技术。后面会讲,今天了解一下。// 画板,画笔,画刷,画开状,画笔或画刷的颜色,粗细Graphics g = e.Graphics;// 画布SetGraphics(g);// 对画布做一些设置SolidBrush brush = new SolidBrush(TextColor);// 画刷RectangleF rectF = new RectangleF(5, 5, this.Width - 10, this.Height - 10);g.FillRectangle(new SolidBrush(Color.Gray), rectF);  // 把矩形填充颜色g.DrawString(MyText, font, brush, rectF, Format);}// 公开的3个属性TextColor、MyText、Format(只读)private Color textColor = Color.FromArgb(22, 95, 162);[Description("文本颜色")]public Color TextColor{get { return textColor; }set{textColor = value;Refresh();//Update();//Invalidate();}}[Description("文本内容")]public string MyText{get{return this.Text;}set{this.Text = value;Refresh();}}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;}}}
  • 属性显示在杂项中如下图
    在这里插入图片描述

自定义组件

 // 组件:一般情况组件不带界面效果,只带业务逻辑// 自己封装了一个定时器组件。public partial class MyTimer : Component{//System.Windows.Forms.Timer工具箱中的定时器//System.Timers.Timer//System.Threading.Timerprivate Timer _timer = new Timer();public event EventHandler TimerTick;// 无参构造函数,给代码public MyTimer(){InitializeComponent();// 实例化一个定时器_timer = new Timer(TimerInterval);// Elapsed事件相当于System.Windows.Forms.Timer定时器中的Tick事件_timer.Elapsed += _timer_Elapsed;}private void _timer_Elapsed(object sender, ElapsedEventArgs e){TimerTick?.Invoke(sender, e);}// 有参构造函数,给设计器用的public MyTimer(IContainer container){// 把当前的组件this添加容器container中container.Add(this);InitializeComponent();// 实例化一个定时器_timer = new Timer(TimerInterval);// Elapsed事件相当于System.Windows.Forms.Timer定时器中的Tick事件_timer.Elapsed += _timer_Elapsed;}[Description("定时器间隔时间,单位毫秒,默认值1000")]public double TimerInterval{get { return _timer.Interval; }set { _timer.Interval = value; }}[Description("是否启用定时器")]public bool TimerEnabled{get{return _timer.Enabled;}set{_timer.Enabled = value;}}}

4。反射?

反射是指在程序运行中,查看、操作其他程序集或者自身的元数据的各种信息(类、方法,属性、变量、对象等)的行为。C#中的反射(Reflection)是一种强大的特性,允许你在运行时检查和操作程序集、类型和对象的信息,基本上,使用反射可以在代码运行时检查和操作指定的类及其成员。C#反射的原理主要基于元数据(与C#特性相似),即程序集中存储的有关类型、方法等的信息。因为反射可以在程序编译后获得信息,所以它提高了程序的拓展性和灵活性。

  // 反射最大的目的为了解耦。// 加载Model.dll程序集,只有加载了程序集,才能创建程序集中某个类的实例。Assembly assembly = Assembly.Load("Model");// 拿Model.Student的实例,相当于 Student s = new Student();object stu = assembly.CreateInstance("Model.Student");// 拿到Model.Student的实例的类型,类型Model.StudentType type = stu.GetType();// 拿到实例的Name属性PropertyInfo name = type.GetProperty("Name");// 设置Name属性的值为张三,相当于s.Name = "张三";name.SetValue(stu, "张三");// 拿到Name属性的值,输出张三Console.WriteLine(name.GetValue(stu));  MethodInfo method = type.GetMethod("ToString");Console.WriteLine(method.Invoke(stu, null));// 获取所有的方法和属性MethodInfo[] methodInfos = type.GetMethods();PropertyInfo[] propertyInfos = type.GetProperties();

反射就是为了拿到各种元素对应的标签。Reflection反射
https://blog.csdn.net/qq_57671924/article/details/134208556
https://blog.csdn.net/naer_chongya/article/details/130532672

5。练习题:
a.圆角按钮:(自定义控件应用)
https://blog.csdn.net/shi_xi_sheng/article/details/130969580

b.单行文本框定高、文本垂直居中问题:(自定义控件应用)
https://www.cnblogs.com/weekend001/p/3518020.html
https://blog.csdn.net/mazhiyuan1981/article/details/124350065
https://blog.csdn.net/ngl272/article/details/125226552

c.winform界面美化技巧:IrisSkin4皮肤
https://blog.csdn.net/weixin_37864926/article/details/131822828

d.winform UI库:
https://www.cnblogs.com/bfyx/p/11361809.html
https://www.cnblogs.com/dxqNet/p/17088088.html
https://www.zhihu.com/question/267772520/answers/updated

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89039.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络资产测绘工具全景解析:七大平台深度洞察

​一、资产测绘工具的核心价值​网络资产测绘&#xff08;Cyber Asset Intelligence&#xff09;技术通过主动扫描与被动分析&#xff1a;实时发现全球暴露的网络设备&#xff08;服务器、摄像头、IoT设备&#xff09;自动化构建资产指纹库&#xff08;操作系统/服务/框架版本&…

编程语言设计目的与侧重点全解析(主流语言深度总结)

编程语言的设计本质上是对计算逻辑的形式化表达与工程约束的平衡&#xff0c;不同语言因目标场景、时代需求和技术哲学的差异&#xff0c;形成了独特的设计范式。以下从系统级、应用级、脚本/动态、函数式、并发/安全等维度&#xff0c;选取10种最具代表性的编程语言&#xff0…

重学前端003 --- 响应式网页设计 CSS 颜色

文章目录文档声明head颜色模型div根据在这里 Freecodecamp 实践&#xff0c;记录笔记总结。 文档声明 在文档顶部添加 DOCTYPE html 声明 <!DOCTYPE html>head title 元素为搜索引擎提供了有关页面的额外信息。 它还通过以下两种方式显示 title 元素的内容&#xff1a…

这个Pandas函数可以自动爬取Web图表

Pandas作为数据科学领域鳌头独占的利器&#xff0c;有着丰富多样的函数&#xff0c;能实现各种意想不到的功能。 作为学习者没办法一次性掌握Pandas所有的方法&#xff0c;需要慢慢积累&#xff0c;多看多练。 这次为大家介绍一个非常实用且神奇的函数-read_html()&#xff0…

vLLM与SGLang在自然语言处理领域的技术架构与性能对比研究

随着大语言模型在工业界和学术界的广泛应用&#xff0c;高效推理框架的选择成为自然语言处理领域的关键挑战。vLLM与SGLang作为当前最前沿的推理优化框架&#xff0c;分别通过创新的PagedAttention和RadixAttention机制展现了独特的技术优势。本文将系统对比两大框架的核心架构…

楼宇自动化:Modbus 在暖通空调(HVAC)中的节能控制(二)

Modbus 在 HVAC 节能控制中的应用案例案例一&#xff1a;某商业建筑 HVAC 系统节能改造某大型商业建筑&#xff0c;总建筑面积达 5 万平方米&#xff0c;涵盖了购物中心、餐饮区和娱乐场所等多种功能区域 。改造前&#xff0c;其 HVAC 系统采用传统的控制方式&#xff0c;设备之…

win10安装Elasticsearch

1 启动elasticsearch 下载地址&#xff1a;Download Elasticsearch | Elastic 双击elasticsearch.bat elasticsearch黑窗口启动乱码问题解决方案 到 config 文件下找到 jvm.options 文件 打开后 在文件末尾空白处 添加 -Dfile.encodingGBK 保存后重启即可。 启动后输入&am…

[Meetily后端框架] Whisper转录服务器 | 后端服务管理脚本

第七章&#xff1a;Whisper转录服务器 欢迎回来&#xff01; 到目前为止&#xff0c;我们已经深入探索了"meeting-minutes"项目的"大脑"——Python后端。 我们已经了解了它如何通过后端API网关接收文本转录&#xff0c;使用摘要数据结构&#xff08;Pyd…

Azure-ADF 抽取数据

1,Azure 访问地址 1,国际版 https://portal.azure.com/#homehttps://portal.azure.com/#home2,世纪互联中国版 Microsoft Azure 由世纪互联运营https://portal.azure.cn/2,创建资源组并且所有的后续组件都是再此资源下面创建。 3,创建Data Factory 工具 4,核心组件 1. 管…

django queryset 去重

在Django中&#xff0c;使用QuerySet时&#xff0c;如果你想要对查询结果进行去重&#xff08;即去除重复的记录&#xff09;&#xff0c;你可以使用几种不同的方法。这里列出了一些常见的方法&#xff1a; 使用distinct() distinct()方法用于返回QuerySet中不重复的唯一对象。…

WIFI MTU含义 ,协商修改的过程案例分析

WIFI MTU含义 ,协商修改的过程案例分析 文章目录 **WIFI MTU含义 ,协商修改的过程案例分析****一、WIFI MTU的含义****二、MTU协商修改的过程案例分析****1. TCP/IP协议中的MTU协商****2. 蓝牙(BLE)中的MTU协商****3. 网络设备配置中的MTU调整****三、协商修改的注意事项**…

记一次Android Studio编译报错:Execution failed for task ‘:app:compileDebugAidl‘

问题背景: android studio导入AIDL文件的时候编译提示: Execution failed for task :app:compileDebugAidl. > A failure occurred while executing com.android.build.gradle.tasks.AidlCompile$AidlCompileRunnable > com.android.ide.common.process.ProcessEx…

selenium跳转到新页面时如何进行定位

在 Selenium 中&#xff0c;当你跳转到新页面&#xff08;例如通过点击链接、提交表单或 JavaScript 重定向&#xff09;时&#xff0c;通常会遇到页面加载或窗口切换的问题。为了在新页面上继续进行页面定位操作&#xff0c;你需要确保以下几点&#xff1a;✅ 1. 等待页面加载…

QT——QComboBox组合框控件

QComboBox概述QComboBox是Qt框架中提供的组合框控件&#xff0c;它结合了按钮和下拉列表的功能&#xff0c;允许用户从预定义的选项列表中选择一个或多个项目。基本特性特性描述显示方式显示当前选中项&#xff0c;点击后展开下拉列表编辑能力可设置为可编辑或不可编辑项目类型…

CentOS 安装jenkins笔记

1. 安装 Java。目前一般jdk要求11以上&#xff0c;否则会报错2. 手动添加 Jenkins 仓库先创建一个专门的Jenkins文件夹&#xff1a;mkdir jenkins然后 执行 sudo curl -fsSL https://pkg.jenkins.io/redhat/jenkins.io.key -o /etc/pki/rpm-gpg/jenkins.io.key 然后&#xff0…

C#枚举:从基础到高级的全方位解析

C#枚举&#xff1a;从基础到高级的全方位解析 在 C# 编程中&#xff0c;枚举&#xff08;Enum&#xff09;是一种特殊的值类型&#xff0c;用于定义命名的常量集合&#xff0c;它为代码提供了更强的类型安全、可读性和可维护性。从简单的状态标识到复杂的位运算组合&#xff0c…

[spring6: Resource ResourceLoader ResourceEditor]-加载资源

Resource Resource 接口为处理和访问不同类型资源&#xff08;如文件、URL、输入流等&#xff09;提供了统一的 API&#xff0c;支持资源的存在性检查、读取、转换等操作。 public interface Resource extends InputStreamSource {boolean exists();default boolean isReadable…

Spring Boot - Spring Boot 集成 MyBatis 分页实现 PageHelper

一、PageHelper 概述 PageHelper 是一个优秀的 MyBatis 分页插件&#xff0c;可以方便地在 Spring Boot 项目中使用 MyBatis 结合 PageHelper 实现分页功能二、PageHelper 引入 1、依赖引入 pom.xml <properties>...<postgresql.verison>42.5.6</postgresql.ver…

jenkins自动化部署前端vue+docker项目

文章目录一、准备工作二、编写dockerfile文件三、新建jenkins任务一、准备工作 默认你的服务器centos已经搭建完成&#xff0c;同时已经安装了jenkins和docker。 接下来去下载开源项目ruoyi并上传到自己的gitee中。 二、编写dockerfile文件 打开项目工程&#xff0c;在rouy…

opencv中contours的使用

一 Contour FindingContours使用 STL-style vector<> 表示&#xff0c;如 vector<cv::Point>, vector<cv::Point2f>。opencv中&#xff0c;使用函数 cv::findContours() 寻找contours&#xff0c; 具体函数定义如下&#xff1a;void cv::findContours(cv::In…