继承现有的控件

继承现有的控件


   

1、基本步骤

(1)创建或打开一个Windows Control Library项目,给项目添加一个新的自定义控件。所创建的类继承于System.Windows.Forms.Control基类。指定继承类的代码行必须改为继承于用作起点的控件。

(2)在类文件中添加必须的新逻辑,以增加新的功能,之后用Build操作编译项目,创建包含新控件代码的DLL文件。

(3)控件现在准备就绪了,它能够用Visual Studio 2008中的Choose Items选项放在Windows Forms工具箱中。从此以后,它能够像其他控件一样拖放到窗体上。

在上面的步骤中,第二步是最主要的。为定制控件添加的逻辑包括新的属性、方法和事件,有时还需要监听基类控件的事件并进行合适的处理。所有这些任务都依赖于标准的.NET编码技术。

 

2、给派生的控件添加代码

 

(1)为自定义控件创建属性

为自定义控件创建属性就像为其他的类创建属性一样,需要编写一个属性过程,在某个地方存储属性的值,一般是在模块级得变量中存储,该变量常常称为支持字段。

属性一般需要默认值,默认值就是当实例化一个控件时会自动赋予属性的值。这一般是指设置支持字段,并把属性值存储为初始值。可以在声明支持字段时,或在控件的构造函数中初始化默认值。

下面是一个简单的自定义控件的属性代码:

image

一旦为控件创建了一个属性,该属性就会自动显示在控件的Properties窗口中。如果属性窗口是按字母顺序排列属性的,就可以在属性列表中看到它。如果属性窗口是按类别排序的,新属性就显示在Misc类别中。还可以使用一些附加的功能,使该属性在Visual Studio的设计器和Properties窗口中工作得更好。

 

(2)协调属性与Visual Studio IDE的交互

控件一般拖放到可视化设计界面上,由Visual Studio IDE管理。为了使控件与IDE很好地交互,必须告诉IDE它的默认属性值。IDE通过两种主要的方式来使用属性的默认值:

  • 重新设置属性的值(用户在Properties窗口中右击属性,并选择Reset菜单项)。
  • 确定是否在设计器生成的代码中设置属性。使用默认值的属性一般不需要在设计器生成的代码中显式设置。

有两种方法来完成这些任务。对于带有简单值的属性,例如整数、布尔值、浮点数或字符串,.NET提供了属性(attribute);对于带复杂类型的属性,例如结构、枚举类型或对象引用,则需要实现两个方法。

 

特性

像组件一样,特性也位于名称空间中。项目必须引用包含该特性的名称空间的程序集。System.ComponentModel的使用不会有任何问题,因为项目会自动包含该引用。

但是,项目不会自动为这个名称空间添加Imports语句。特性可以使用完整的类型名称来引用,但这比较繁琐。为了便于在代码中引用特性,应把下面的代码放在本章中所有需要使用该特性的模块开头:

Imports System.ComponentModel

接着,特性就可以用其名称来引用了。例如

image

属性的特性必须位于声明属性的代码行上。当然,可以使用续行符,让特性放在单独的一行上,但仍属于程序中的同一逻辑代码行上。例如:

image

 

(3)使用特性设置默认值

.NET Framework中有许多特性,大都用于把元数据赋给类、属性和方法,所以有时需要了解其他实体。

image

包含DefaultValue特性,就会在控件的Properties窗口中把属性值重新设置为默认值。也就是说,如果在Properties窗口中右击属性,选择关联菜单中的Reset菜单项,属性值就会从原来设置的值返回为默认值10.

特性的另一个作用可以在可视化设计器生成的代码中看出。如果上面的属性设置为不是默认值的其他值,在设计器生成的代码中就会出现一行设置属性值的代码。这称为串行化属性。

如果MaxItemsSelected的值设置为5,在设计器生成的代码中就会出现如下代码:

image

如果属性的默认值为10,设置属性值的代码行就不会出现在设计器生成的代码中。即如果属性值是默认的,就不需要在代码中进行串行化。

 

(5)IDE中的其他相关技术

上面例子中的属性返回一个整数。一些自定义的属性返回比较复杂的类型,例如结构、枚举类型或对象引用。这些属性不能用简单的DefaultValue特性来重新设置和串行化属性,而需要另一种方法。

对于复杂的类型,设计器在包含属性的控件中使用方法来确定属性是否需要串行化。该方法返回的布尔值表明属性是否需要串行化(如果需要,该布尔值就为True,否则就为False)。

对于下面的例子,假设一个控件有一个Color类型的MyColor属性,Color类型在Windows窗体中是一个结构,所以不能给它使用一般的DefaultValue特性。进一步假设该属性的支持变量是_MyColor。

用于检验串行化的方法称为ShouldSerializeMyColor。该方法如下所示:

image

这说明DefaultValue特性为什么不能用于所有的类型。Color类型没有对应的运算符,所以必须编写适当的代码,执行检查,确定MyColor属性的当前值是否为默认值。这里用Color类型的Equals方法来实现。

如果自定义控件中的属性没有相关的ShouldSerializeXXX方法或DefaultValue特性,其属性将总是进行串行化。设置属性值的代码 总是被设计器包含在窗体的生成代码中。因此,最好始终为控件创建的每个新属性包含ShouldSerializeXXX方法或DefaultValue特 性。

 

为控件属性提供重置方法

ShouldSerialize方法仅告诉IDE是否要串行化属性值。需要ShouldSerialize方法的属性还需要一种方法,将属性的值重新设置为默认值。这需要一个特殊的重置方法。对于MyColor属性,重置方法是ResetMyColor。该方法如下所示:

image

 

3、其他有用的特性

DefaultValue不是用于属性的唯一特性。Description特性也是一个常用的特性。当属性被选中时,它包含了属性的文本描述,显示在Properties窗口底部。为了包含一个Description特性,上述属性的声明应如下所示:

image

image

有时还需要另一个特性Browsable。如前所述,新属性会自动显示在Properties窗口中。在一些情况下,需要为控件创建一个不显示在 Properties窗口中的特性。此时可以把特性Browsable设置为False。下面的代码与前面类似,使属性不能在Properties窗口浏 览:

image

最后一个可能会用到的特性是Category。单击Properties窗口顶部的按钮,可以把属性按照类别分组。标准的类别包括Behavior、 Appearance等。我们可以让属性归类到任何一个类别里,也可以创建一个新的分组。要把属性归类到一个类别中,可以使用下面的代码:

image

 

4、为派生的控件自定义事件

对于控件、创建和处理事件的过程如下所示:

(1)声明控件中的事件。事件可以拥有任何适当的参数,但是它们不能拥有已命名的参数、可选参数,或ParamArrays参数。事件的命名一般遵循.NET Framework的命名约定,但这不是必需的。下面是用于声明一般事件的代码:

image

(2)在控件代码的其他地方,执行用于引发事件的代码。该代码的位置和内容随事件的不同而不同,引发上述事件的代码行如下所示:

image

(3)包含控件的窗体现在能够处理事件。处理的过程与处理内置控件的事件相同。

如前面的例子所述,在.NET中,事件的标准约定是包含两个参数,一个是引发事件的对象Sender,另一个是类型的EventArgs类型的对象e。语法上没有这个要求(实际上可以使用任意参数),但在.NET Framework中这是一个一致的约定。最好遵循这个约定,因为这会使定制控件与内置控件的操作一致。

 

5、限制选中项数的CheckedListBox

这个例子继承CheckedListBox内置控件,并扩展它的功能。如果不熟悉这个控件,只要知道,除了所选项是用列表项前面的选中复选框来表示,而不是突出显示之外,它工作起来就像标准的ListBox控件一样。

为了扩展这个控件的功能,下面创建一个MaxItemSelected属性。该属性将保存用户最多可以选择多少个列表项。当用户选取一个列表项时,触发的事件会监控是否已经达到了最大值。

如果选择了另一列表项,使所选项的个数超过了最大值,选择将被阻止,并触发一个事件,告知用户已经超过了最大限制。然后窗体中的处理事件的代码可以作任何适当的处理。在本例中,只是显示一个消息框,告知用户不能再选择列表项了。

给MaxItemsSelected属性添加DefaultValue、Description和Category特性,以便与IDE交互操作。

这里是示例的具体构建步骤:

(1)在Visual Studio中启动一个新的Windows Control Library项目。给它命名为MyControls,在Solution Explorer中,选中UserControl.vb文件,右击它,删除之。

(2)选择Project|Add New Item菜单项,选择项目模板Custom Control,将该项目命名为LimitedCheckedListBox。

(3)单击Solution Explorer中的Show All Files按钮,显示项目中的所有文件,单击LimitedCheckedListBox.vb旁边的加号,打开LimitedCheckedListBox.Designer.vb。

(4)在LimitedCheckedListBox.Designer.vb代码的顶端,找到代码行:

image

(5)把这行代码改为:

image

(6)在代码的顶端添加如下声明(在声明类得代码行前面):

image

这就允许利用System.ComponentModel名称空间中的特性。

(7)LimitedCheckedListBox.vb包含绘制控件的事件。我们不希望控件绘制它自己的界面,所以删除该事件。

(8)开始添加控件特定的代码。首先需要实现MaxItemsToSelect属性,需要用一个模块级的变量来保存属性值,所以应将下面的代码放在类声明的下面:

image

(9)现在为属性创建代码。将下面的代码放在类中End Class代码行的前面

image

该代码将MaxItemsToSelect属性的默认值设置为4,并且设置属性的文字说明,在Properties窗口中选择该属性后,就会显示该文字说明。还指定,在Properties窗口中按类别排序时,该属性显示在Behavior类别中。

(10)现在需要声明当用户选择太多的列表项时触发的事件。该事件命名为MaxItemsExceeded。在第(9)步代码的下面插入如下的代码行:

image

(11)在用户单击列表项时引发的事件例程中插入代码。对于CheckedListBox基类,这就是ItemCheck属性。打开代码窗口左侧的下拉列表框,并选择LimitedCheckedListBox Events选项,然后在代码窗口的右侧下拉列表框中选择ItemCheck事件,这会插入下面处理ItemCheck事件的代码:

image

(12)把下面的代码添加到ItemCheck事件中,以监控是否选择了过多的列表项:

image

image

(13)构造项目,以创建一个包含LimitedCheckedListBox控件的DLL文件。

posted @ 2012-03-01 16:17  晴天有时下鱼  阅读(298)  评论(0编辑  收藏  举报