自定义控件基础知识 一 、概述 · 组合现有控件来创作一个复合控件。 复合控件封装有一个可以作为控件重复使用的用户界面。可视化设计器为创建复合控件提供了有力的支持。要创作一个派生自 System.Windows.Forms.UserControl 的复合控件。基类 UserControl 为子控件提供了键盘路由并使子控件可以作为一个组进行工作。 · 扩展现有控件,对其进行自定义或为其添加功能。 可以通过从任何 Windows 窗体控件派生控件并重写或添加属性、方法和事件的方式来自定义 Windows 窗体控件。 · 创作一个不是通过组合或扩展现有控件而形成的控件。 在这种方案中,需从基类 System.Windows.Forms.Control 派生控件。可以添加和重写基类的属性、方法和事件,来制作功能强大,能满足自己需求的控件。 Windows 窗体控件的基类 System.Windows.Forms.Control 为客户端 Windows 应用程序中的外观显示提供了所需的途径。Control 提供了一个窗口句柄,用来处理消息路由并提供鼠标和键盘事件及许多其他用户界面事件。还提供了高级布局,并具有用于外观显示的特定属性,如 ForeColor、BackColor、Height、Width 和许多其他属性。此外,它还提供了安全性、线程支持以及与 ActiveX 控件的交互性。由于基类提供了很多基础结构,使得开发自己的 Windows 窗体控件变得相对简单。
二、编写简单的自定义控件
e.Graphics.DrawString(this.Text, Font, new SolidBrush(ForeColor), rect); 2. 出现“新建项目”对话框。 3. 在“名称”框中,键入项目名称,“位置”框选择要存储的位置。 4. 从“语言”列表中选择要使用的编程语言。 5. 单击“添加”,这时一个自定义控件工程已经建成,生成一下,就制作了一个简单的自定义控件,只不过没有任何功能。 6. 向新用户控件添加任何标记和控件,并为该用户控件添加执行的所有任务(例如,处理控件事件或从数据源读取数据)添加代码。 2.3、检查控件的设计时行为 2. 通过从“文件”菜单单击/新建/项目/Windows应用程序,添加新窗体。 3. 右键“工具箱/选择项…”,在弹出的“选择工具箱项”对话框中点下面的浏览按钮选择要使用控件的 DLL;确定后,该控件出现在工具箱的底部。 4. 选择该控件并将其添加到窗体中。将看到该控件出现在窗体上。 5. 如果从上一个示例添加控件,您将注意到即使如此简单的控件都具有一整套属性和广泛的设计时行为。此默认行为是从 Control 类继承的。 三、为控件添加属性 属性定义通常由以下两部分组成: 2、使用属性声明语法对公共属性进行的定义。
value 这个术语是属性定义语法中的一个关键字。在呼叫代码中,将变量 value 分配给属性。value 的类型必须同它被分配到的属性的声明类型相同。 虽然属性定义中通常包含专用数据成员,但这不是必需的。get 访问器不用访问私有数据成员就可以返回值。get 方法返回系统时间的属性就属于这种情况。属性启用数据隐藏,访问器方法隐藏属性的实现。 定义属性时需考虑以下重要的注意事项: 1、 必须将属性应用于定义的属性。属性用来指定设计器显示属性的方式。 2、 如果改变属性将影响控件的外观显示,请从 set 访问器中调用 Invalidate 方法(从 Control 继承该方法)。Invalidate 随后调用 OnPaint 方法,该方法将重新绘制控件。为提高效率起见,对 Invalidate 的多次调用将产生对 OnPaint 的一次调用。 3、 .NET Framework 类库为常见数据类型(如整数、小数、布尔值和其他数据)提供了类型转换器。类型转换器的目的通常是用来提供字符串到数值的转换(从字符串数据转换为其他数据类型)。常见数据类型与默认类型转换器(将数值转换为字符串,并将字符串转换为相应数据类型)相关联。如果定义了自定义(即,非标准)数据类型的属性,则应用的属性必须将类型转换器指定为与该属性相关联。还可以使用属性使自定义 UI 类型编辑器与某个属性相关联。UI 类型编辑器提供了一个用来编辑属性或数据类型的用户界面。颜色选择器是 UI 类型编辑器的一个示例。 例:首先创建一个名为 DrawingMode 的简单枚举。
对 SetColors 方法的调用只是根据 myDrawingMode 的值设置控件的 BackColor 和 ForeColor。向控件添加下面的代码。
事件是对象发送的消息,以发信号通知操作的发生。操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。引发事件的对象称为事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。 在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。.NET Framework 定义了一个特殊的类型(Delegate),该类型提供函数指针的功能。 代理(delegate) delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。与其它的类不同,delegate类能够拥有一个签名(signature),并且它只能持有与它的签名相匹配的方法的引用。这样,代理就等效于一个类型安全函数指针或一个回调。它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。但与函数指针相比,delegate有许多函数指针不具备的优点。首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。其次,与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。 实现一个delegate是很简单的,通过以下3个步骤即可实现一个delegate: 1. 声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。 2. 创建delegate对象,并将你想要传递的函数作为参数传入。 3. 在要实现异步调用的地方,通过上一步创建的对象来调用方法。 下面是一个简单的例子: C#中的事件处理实际上是一种具有特殊签名的delegate,象下面这个样子: public delegate void MyEventHandler(object sender, MyEventArgs e); 其中的两个参数,sender代表事件发送者,e是事件参数类。MyEventArgs类用来包含与事件相关的数据,所有的事件参数类都必须从System.EventArgs类派生。当然,如果你的事件不含特别的参数,那么可以直接用System.EventArgs类作为参数。 结合delegate的实现,我们可以将自定义事件的实现归结为以下几步: 1:定义delegate对象类型,它有两个参数,{dy}个参数是事件发送者对象,第二个参数是事件参数类对象。 2:定义事件参数类,此类应当从System.EventArgs类派生。如果事件不带参数,这一步可以省略。 3:定义事件处理方法,它应当与delegate对象具有相同的参数和返回值类型。 4:用event关键字定义事件对象,它同时也是一个delegate对象。 5:用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。 6:在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是可以是OnEventName。 7:在适当的地方调用事件触发方法触发事件。 下面是一个例子,例子模仿容器和控件的模式,由控件触发一个事件,在容器中捕捉并且进行处理。 事件的触发者:
程序运行的结果如下: please input 'a':a hello Some event occur! 五、其他属性设置
即在控件类前面加上ToolboxBitmap属性,属性参数指向一个图片的地址就可以了,加上这句程序以后,生成的控件如下图,图标变成了一个漂亮的心。
Browsable 适用于属性和事件,指定属性或事件是否应该显示在属性浏览器中。 Category 适用于属性和事件,指定类别的名称,在该类别中将对属性或事件进行分组。当使用了类别时,组件属性和事件可以按逻辑分组显示在属性浏览器中。 Description 适用于属性和事件,定义一小块文本,该文本将在用户选择属性或事件时显示在属性浏览器底部。 Bindable 适用于属性 指定是否要绑定到该属性。 DefaultProperty 适用于属性,(将此特性插入类声明前。)指定组件的默认属性。当用户单击控件时,将在属性浏览器中选定该属性。 DefaultValue 适用于属性,为属性设置一个简单的默认值。 Editor 适用于属性,指定在可视设计器中编辑(更改)属性时要使用的编辑器。 Localizable 适用于属性,指定属性可本地化。当用户要本地化某个窗体时,任何具有该特性的属性都将自动{yj}驻留到资源文件中。 DesignerSerializationVisibility 适用于属性,指定显示在属性浏览器中的属性是否应该(以及如何){yj}驻留在代码中。 TypeConverter 适用于属性,指定将属性的类型转换为另一个数据类型时要使用的类型转换器。 DefaultEvent 适用于事件,(将此特性插入类声明前。)指定组件的默认事件。这是当用户单击组件时在属性浏览器中选定的事件。 |