C#——写一个控件库腾讯云开发者社区

控件库,说白了,就是个类库项目。不过这个类库内定义了一系列自定义的控件。整个项目(类库+调用项目)结构大概是这个样

请忽略Class2和ClassDiagram1.cd,这是我之前一个博文

用到的项目,留下来也无关紧要。UserControl2.cs就是我们的一个控件了。长这个样

一个TextBox下面有一条线,线宽等于文本框的宽等于整个控件的宽。当然,这需要在cs代码中做一些调整(设置属性或是什么)。代码长这个样,仅供参考

privateintwidth;定义了一个字段,用来指示控件的宽度,private。然后定义了一个属性,也是用来指示控件宽度,public。这样在类外访问控件宽度需通过属性,而不是直接把字段暴露给外部。

[Description("控件宽度"),Category("自定义属性")]publicintselfWidth{get{returnwidth;}set{this.width=value;this.Width=value;this.txtBox.Width=value;this.pictureBox.Width=value;}}其中

[Description("控件宽度"),Category("自定义属性")]加上这行表明这个属性代表了控件宽度,后面的Category是分组情况。这行的意义是用了这个控件之后,就能在当前窗体设计器上面方便地改动属性值,就像这样

还有最后一段代码

写控件库一点都不难,只需要同样的过程重复N遍再加上一点创意,必要时还需要用点别人的东西。

今天学习了下C#用户控件开发添加自定义属性的事件,主要参考了MSDN,总结并实验了一些用于开发自定义属性和事件的特性(Attribute)。

在这里先说一下我的环境:

操作系统:Windows7旗舰版(ServicePack1)

VS版本:MicrosoftVisualStudioUltimate2012,版本11.0.50727.1RTMREL

.NETFramework版本:4.5.50938

C#版本:VisualC#2012

1、建立一个C#窗体应用程序,主窗体起名为FormMain,向解决方案中再加入一个用户控件,起名为TestUserControl

2、在TestUserControl中放一个按钮,取名为btnTest

3、控件做好后,会出现在【工具箱】内

4、将控件拖拽到一个窗体(Form)上就可以使用了,取名testUserControl1。这个名字是VS默认取的,即首字母小写,最后补上数字作为序号。

在TestUserControl类中,添加下面的代码:

///

///按钮名称///publicstringButtonName{get{//TODOreturnbtnTest.Text;}set{//TODObtnTest.Text=value;}}代码添加完毕后,在FormMain上加入的testUserControl1的属性中,就会出现BtnName了

///

///事件///publiceventEventHandlerBtnTestClick;//////测试按钮/////////privatevoidbtnTest_Click(objectsender,EventArgse){if(BtnTestClick!=null){//TODOBtnTestClick(sender,e);}}代码添加完毕后,在FormMain上加入的testUserControl1的事件中,就会出现BtnTestClick了

在FormMain的代码中实现这个函数

privatevoidtestUserControl1_BtnTestClick(objectsender,EventArgse){MessageBox.Show(sender.ToString()+"\r\n"+e.ToString());}这时运行程序,点击控件testUserControl1内的按钮btnTest,就会有下面的效果:

[DefaultEvent("BtnTestClick")]那在Form编辑界面,双击控件testUserControl1就会自动进入testUserControl1_BtnTestClick事件。

这里再说明一下,C#中的System.Windows.Forms.Control类代码如下:

[ClassInterface(ClassInterfaceType.AutoDispatch)][ComVisible(true)][DefaultEvent("Click")][DefaultProperty("Text")][Designer("System.Windows.Forms.Design.ControlDesigner,System.Design,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a")][DesignerSerializer("System.Windows.Forms.Design.ControlCodeDomSerializer,System.Design,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a","System.ComponentModel.Design.Serialization.CodeDomSerializer,System.Design,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a")][ToolboxItemFilter("System.Windows.Forms")]publicclassControl:Component,IDropTarget,ISynchronizeInvoke,IWin32Window,IBindableComponent,IComponent,IDisposable{/*...*/}这里可以看到DefaultEvent的值为“Click”,这也就是为什么拖入Form的按钮(Button),在双击后会进入它的Click事件:

[ClassInterface(ClassInterfaceType.AutoDispatch)][ComVisible(true)][DefaultBindingProperty("CheckState")][DefaultEvent("CheckedChanged")][DefaultProperty("Checked")][ToolboxItem("System.Windows.Forms.Design.AutoSizeToolboxItem,System.Design,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a")]publicclassCheckBox:ButtonBase{/*...*/}这里的DefaultEvent被写上了“CheckedChange”,因此在Form的编辑界面,双击复选框时默认进入的编辑事件为

privatevoidcheckBox1_CheckedChanged(objectsender,EventArgse)自定义的控件(直接继承自UserControl),如果不添加这个属性,在编辑界面双击后进入的事件是Load事件。

[Browsable(false)]则控件testUserControl1的属性界面就不会出现BtnName的设置了,下图红线部分为之前BtnName所在的位置

如果某属性或事件没有添加Browsable特性,那么该属性或事件也可以在“属性”窗口中看到。这里还要说明以下,Browsable只能决定某属性或事件在“属性”窗口内的可见性,Browsable被置为false的属性和事件,仍可以在编辑器中通过代码中使用。

如在BtnName上添加下面代码:

[Description("设置按钮上显示的文字")]也可以带上Browsable特性一起使用:

[Browsable(true)][Description("设置按钮上显示的文字")]或写在一对方括号里,用逗号隔开:

[Browsable(true),Description("设置按钮上显示的文字")]在“属性”界面中看到的说明文字,效果如下:

EditorBrowsableAttribute的构造函数如下:

publicEditorBrowsableAttribute(EditorBrowsableStatestate);其中,EditorBrowsableState是一个枚举(enum),这个枚举共有三个值,分别是Always、Never和Advanced

Always:该属性或方法在编辑器中始终是可浏览的

Never:该属性或方法始终不能在编辑器中浏览

Advanced:该属性或方法是只有高级用户才可以看到的功能。编辑器可以显示或隐藏这些属性

前面两个都好理解,第三个Advanced着实会让人一头雾水(什么才叫“高级用户”?)。后来查了一些资料,才知道对于高级成员的可见性,可以在“工具”菜单下的“选项”中进行配置。

如果勾选了“隐藏高级成员”,那么用代码“[EditorBrowsable(EditorBrowsableState.Advanced)]”标记的属性,将不能在IDE中自动显示。但这也仅仅是不自动显示而已,如果在代码中真的调用了不可见的属性,编译不会报错,运行也不会有问题。

如下图:BtnName被标记为“EditorBrowsableState.Never”,因此这个属性不会出现在VS的智能提示(学名叫IntelliSense)中,但如果写到代码里,却没有问题。

需要注意的是,这种隐藏只有在该控件代码为当前解决方案不可见时有效,也就是说,如果这个控件的实现代码就在你的解决方案内,EditorBrowsable并不能保证用户看不见这个属性。但如果这个控件时被放在一个dll文件中添加引用到当前的解决方案中,EditorBrowsable特性才能按其文字描述中说明的那样起作用。

参数为DesignerSerializationVisibility类型的枚举:

Hidden:代码生成器不生成对象的代码

Visible:代码生成器生成对象的代码

Content:代码生成器产生对象内容的代码,而不是对象本身的代码

这个说法一眼看上去并不易理解,因此我决定还是用两个具体例子说明一下:

1、Hidden与Visible、Content的不同

还是以我们上面的BtnName属性为例,参数为【DesignerSerializationVisibility.Hidden】的情况

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]publicstringBtnName{get{returnbtnTest.Text;}set{btnTest.Text=value;}}将控件拖入FormMain的窗体设计器中,可用在文件FormMain.Designer.cs中看到:

///

///设计器支持所需的方法-不要///使用代码编辑器修改此方法的内容。///privatevoidInitializeComponent(){this.testUserControl1=newControlTest.TestUserControl();this.SuspendLayout();////testUserControl1//this.testUserControl1.Location=newSystem.Drawing.Point(33,46);this.testUserControl1.Name="testUserControl1";this.testUserControl1.Size=newSystem.Drawing.Size(134,77);this.testUserControl1.TabIndex=0;//...}将BtnName上方的特性DesignerSerializationVisibilityAttribute的参数改为【DesignerSerializationVisibility.Visible】或【DesignerSerializationVisibility.Content】后,函数InitializeComponent()中的代码会有不同:

///

///设计器支持所需的方法-不要///使用代码编辑器修改此方法的内容。///privatevoidInitializeComponent(){this.testUserControl1=newControlTest.TestUserControl();this.SuspendLayout();////testUserControl1//this.testUserControl1.BtnName="button1";this.testUserControl1.Location=newSystem.Drawing.Point(36,32);this.testUserControl1.Name="testUserControl1";this.testUserControl1.Size=newSystem.Drawing.Size(134,77);this.testUserControl1.TabIndex=0;//...}可用看出,区别就在下面这行代码:

this.testUserControl1.BtnName="button1";使用了Hidden就没有,使用了Visible就会有(使用了Content也会有)

使用了Hidden后,在“属性”界面中,无论怎么修改BtnName属性的值,编译时编译器都不会理睬这个值,而是使用默认值(这个例子里面就是button1)。使用了Hidden后,即使在FormMain.Designer.cs里手动把上面那行赋值的代码加上,这行代码在程序重新编译后还是会消失。

2、Visible与Content的不同

Content被用在可以序列化的集合,例如System.Windows.Forms.DataGridView类(数据表格)

////摘要://获取一个包含控件中所有列的集合。////返回结果://一个System.Windows.Forms.DataGridViewColumnCollection,包含System.Windows.Forms.DataGridView//控件中的所有列。[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)][Editor("System.Windows.Forms.Design.DataGridViewColumnCollectionEditor,System.Design,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a",typeof(UITypeEditor))][MergableProperty(false)]publicDataGridViewColumnCollectionColumns{get;}IDE只是生成这些属性中包含组件的代码,而不会生成属性本身的代码。在使用IDE添加各个DataGridViewTextBoxColumn时,各个DataGridViewTextBoxColumn的代码会被放在FormMain.Designer.cs文件中,而有关Columns属性本身只会在在函数InitializeComponent()中生成这样一段代码:

THE END
1.C#中控件的层级(显示)顺序更改在做用C#做程序设计的时候,可能会在中途插入一些新的控件,但由于新控件的层级默认在原有控件之上,某些情况下会造成麻烦。 比如: 这时候,我们想要插入一个TabControl容器,想要实现以下效果: 但这时候就会发现一个问题:就是文本控件始终在TabControl控件下方,达不到我们需要的效果: https://blog.csdn.net/2301_79760264/article/details/144080279
2.C#面向对象三大特性:封装继承多态面向对象有封装、继承、多态这三个特性,面向对象编程按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成任务。这种编程方法提供了非常强大的多样性,大大增加了代码的重用机会,增加了程序开发的速度,将具备独立性特制的程序代码包装起来,修改部分程序代码时不至于会影响到https://www.u72.net/daima/n258v.html
3.控件从Control类继承的类具有ControlTemplate,它用于定义Control的结构和外观。Control的Template属性是公共属性,因此可以为Control指定非默认的ControlTemplate。 通常可以为Control指定新的ControlTemplate(而不是从控件继承)以自定义Control的外观。 请考虑一个很常用的控件Button。Button的主要行为是当用户单击它时让应用程序采取某https://technet.microsoft.com/zh-cn/magazine/bb613551(pt-br).aspx
4.未来虫教育那些一看就会一放就忘的C语言知识!代码标识符寄定义标识符HSE_VALUE的值为8000000,数字后的U表示unsigned的意思。至于define宏定义的其他一些知识,比如宏定义带参数,这里就不多讲解了。 03 ifdef条件编译 程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。 https://www.163.com/dy/article/JI6I8VE205566XY7.html
5.无法在WPF中创建继承的用户控件,本地命名空间中的基本控件“不C# 冉冉说 2022-12-31 13:51:53 我试图在继承自基类的 WPF 中创建自定义用户控件“UserControl1”。除其他外,我在 XAML 中收到此错误:错误 XDG0008 命名空间“clr-namespace:Temp”中不存在名称“ControlBase”。我在 DesignHeight & Width 也遇到错误ControlBase 类在 VS 自动完成中可用。ControlBase 类在https://www.imooc.com/wenda/detail/699618
6.C#继承基本控件实现自定义控件黄文博C#继承基本控件实现自定义控件 摘自:http://www.cnblogs.com/greatverve/archive/2012/04/25/user-control-inherit.html 自定义控件分三类: 1.复合控件:基本控件组合而成。继承自UserControl 2.扩展控件:继承基本控件,扩展一些属性与事件。比如继承Button https://www.cnblogs.com/nov5026/p/4700897.html
7.C#用户控件之温度计设计C#教程这篇文章主要为大家详细介绍了C#用户控件之温度计的设计方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想靠AI翻身,你先需要一个靠谱的工具!】 本文以一个用户控件【User Control】实现温度计的小例子,简述用户控件的相关知识,以供学习分享使用,https://www.jb51.net/article/136695.htm
8.无法在WPF中创建继承的用户控件,本地命名空间中的基控件“不存在”命名空间:在WPF中,命名空间用于组织和管理控件和其他类型。通过引用命名空间,我们可以在XAML中使用其中定义的控件。 现在回到问题本身,当在WPF中无法创建继承的用户控件,并且基控件在本地命名空间中“不存在”时,可能有以下几个原因: 命名空间引用问题:确保在XAML文件的开头https://cloud.tencent.com.cn/developer/information/%E6%97%A0%E6%B3%95%E5%9C%A8WPF%E4%B8%AD%E5%88%9B%E5%BB%BA%E7%BB%A7%E6%89%BF%E7%9A%84%E7%94%A8%E6%88%B7%E6%8E%A7%E4%BB%B6%EF%BC%8C%E6%9C%AC%E5%9C%B0%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E4%B8%AD%E7%9A%84%E5%9F%BA%E6%8E%A7%E4%BB%B6%E2%80%9C%E4%B8%8D%E5%AD%98%E5%9C%A8%E2%80%9D-article
9.在C#中编写新控件时,生成时发生错误,如何解决?在C#中编写新控件时,生成时发生错误,如何解决? 代码和错误是: using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace WindowsFormshttps://www.lampchina.net/ask/MTY0ODAxNQ.html
10.C#中面试的常见问题001如果在较低级别(子控件)处理了事件,较高级别(父控件)仍然会接收到事件。 冒泡事件的典型用途是处理用户界面中的鼠标和键盘事件。 隧道事件(Tunneling Events) 隧道事件是指事件从最一般的事件源开始,然后逐级向下传播到较为具体的事件源。在用户界面中,这意味着事件从根控件开始,然后逐级向下传播到目标控件。 http://www.mynw.cn/server/18382.html
11.C#中DataSet转化为实体集合类的方法答:密封,不能继承。 91.在Asp.net中所有的自定义用户控件都必须继承自___? 答:Control。 92.在.Net中所有可序列化的类都被标记为___? 答:[serializable] 93.在.Net托管代码中我们不用担心内存漏洞,这是因为有了___? 答:GC。 94.下面的代码中有什么错误吗?___ using System; class A { public virhttps://www.iteye.com/resource/weixin_38514523-12807920
12.C#将用户自定义控件添加到工具箱中C#中自定义控件VS用户控件大比拼 1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Controls控件 自定义控件(Custom Control):继承自 Control,主要用于开发windows控件的最基本的类,比如 Text,Button 控件 https://www.pianshen.com/article/6762718741/
13.2024年C#面试题参考.doc答:密封,不能继承。? 91.在A中所有的自定义用户控件都必须继承自___ 答:Control。? 92.在.Net中所有可序列化的类都被标识为___? 答:[serializable]? 93.在.Net托管代码中我们不用担心内存漏洞,这是因为有了___ 答:GC。? 94.下面的代码中https://max.book118.com/html/2024/0422/8013032061006061.shtm
14.C#中ComponentClassUserControl及CustomControl的区别.NET Framework 为您提供了开发和实现新控件的能力。除了常见的用户控件外,现在您会发现,您可以编写能执行自身绘图的自定义控件,甚至还可以通过继承扩展现有控件的功能。确定创建何种类型的控件可能会费一番功夫。本节重点介绍了各类可继承控件间的区别,同时提供关系到为项目选择的类型的注意事项。 https://blog.51cto.com/gjwrxz/6284596
15.C#教程之简介Winform中创建用户控件1、创建一个项目,该项目主要用来设计用户控件。 2、创建一个用户控件窗体,用来设计用户控件。 3、向用户控件窗体中添加一个按钮(button1),给它添加相应的移入、移出事件,实现移入时按钮的背景设置一个图片,移出的时候背景设置另一个图片。 复制代码代码如下: https://www.xin3721.com/ArticleHB/hb6423.html