350 likes | 531 Views
组件开发的经验和思想. 青岛微软开发者俱乐部 张磊 (xiaopang). 组件开发中的几点经验. 接口在组件开发中的使用 使用组件来完成简单但繁琐的处理 给二次开发提供方便 使用可视化界面进行组件的属性设置 System.Windows.Forms.ControlPaint 组件功能最大化,可通过开关属性控制 组件形成系列化,易于协作. 有时候我们为了处理方便,或者为了让现在的组件能和将来用户自定义的组件进行通讯,我们可以采用接口的方式来处理,下面通过几个例子来说明一下. 接口在组件开发中的使用.
E N D
组件开发的经验和思想 青岛微软开发者俱乐部 张磊(xiaopang)
组件开发中的几点经验 • 接口在组件开发中的使用 • 使用组件来完成简单但繁琐的处理 • 给二次开发提供方便 • 使用可视化界面进行组件的属性设置 • System.Windows.Forms.ControlPaint • 组件功能最大化,可通过开关属性控制 • 组件形成系列化,易于协作
有时候我们为了处理方便,或者为了让现在的组件能和将来用户自定义的组件进行通讯,我们可以采用接口的方式来处理,下面通过几个例子来说明一下有时候我们为了处理方便,或者为了让现在的组件能和将来用户自定义的组件进行通讯,我们可以采用接口的方式来处理,下面通过几个例子来说明一下 接口在组件开发中的使用
比如,如果我们想让我们的系统以资源的方式支持多国语言,就可以给每一个可视化组件加上资源ID和资源类型的属性,如下图 对于那些需要显示文本的控件(当然,那些显示图片、播放声音等的控件也可以采用类似的方法),如label、button、form等等,都需要这两个属性。因此,我们可以定义一个接口来表示这两个属性:
下面是一个自定义的Label类的部分代码,它实现了上面的资源接口下面是一个自定义的Label类的部分代码,它实现了上面的资源接口
可视化控件总是放到某个容器上的,要想实现国际化的版本,就需要这些容器来完成可视化控件总是放到某个容器上的,要想实现国际化的版本,就需要这些容器来完成 国际化界面的显示。因为容器很多,所以我们让这些容器也实现一个显示自己子控件 国际化属性的接口: 对于实现了这个接口的容器控件,我们可以通过调用ShowChildByResource 方法来让它的子控件显示国际化的界面。 下面是一些容器类(如Form,GroupBox,Panel等)显示国际化界面的代码
上面这段代码有比较长的一段注释,这些注释也是编写组件很重要的一部分,它说明了这个方法的用法,并给出了一个示例,我们也可以根据这些注释来自动生成和vs.net里基本一样的帮助文件来,这个工具叫NDoc,我做了一些汉化,可以在下面这个网址找到下载(下图是生成的帮助文件截图):上面这段代码有比较长的一段注释,这些注释也是编写组件很重要的一部分,它说明了这个方法的用法,并给出了一个示例,我们也可以根据这些注释来自动生成和vs.net里基本一样的帮助文件来,这个工具叫NDoc,我做了一些汉化,可以在下面这个网址找到下载(下图是生成的帮助文件截图): http://blog.csdn.net/tashanzhishi/archive/2005/08/20/459485.aspx
例如,我们设计了一个组件GStandKey,它的某一个功能是可以显示查询窗口,并且返回用户在查询窗口选定的数据集合;根据这个要求我们可以设计出一个和它交互的数据查询窗口控件来,该控件运行界面如图:例如,我们设计了一个组件GStandKey,它的某一个功能是可以显示查询窗口,并且返回用户在查询窗口选定的数据集合;根据这个要求我们可以设计出一个和它交互的数据查询窗口控件来,该控件运行界面如图: • 接口更重要的作用还不是这个,而是在组件的互操作性方面,我们也通过简单的示例来说明 当然,这个控件功能很多,支持时间查询,也支持多列,这个控件能够完成我们大部分查询要求。不过,实际业务逻辑是复杂的,在一些特殊的情况下,这个界面可能就不能满足我们的要求了。那么怎么办呢?我想可以使用接口来解决这个问题。我们可以把需要和这个窗口交互的东西都以接口的形式公开出来,任何实现了这个接口的窗口都可以和GStandKey组件进行通讯。这个接口我们可以这样设计:
这样以来,不管将来的查询窗口怎样设计,也不管具体的业务逻辑如何,只要这些窗口实现了这个接口,我们就可以在这些组件里使用将来的查询窗口了
使用组件来完成简单但繁琐的处理 在软件开发中,有一些工作虽然简单,但因为这些工作量很大,需要重复做很多次,比较耗费时间。对于这样的情况,我们可以使用组件来简化我们的工作,下面也通过示例说明
在.net里进行数据绑定虽然比较简单,但如果要处理的数据字段比较多的话,或者一个数据集有多个数据表的话,进行绑定还是有些繁琐的;特别是用代码来一个个实现绑定的话,代码量就更大了。但这些东西我们都可以使用一个专门用来绑定的组件来完成。我们让所有可能需要绑定数据的控件都实现一个接口,这个接口记录了该控件需要绑定到的数据对象,如下所示 : 数据绑定组件要做的工作就是,把给定的窗体上需要帮定的控件都绑定到指定的数据集上 ,代码如下:
这样就可以很容易的完成数据的绑定,你要做的工作只是给组件的DataMember属性赋上值即可,如图:这样就可以很容易的完成数据的绑定,你要做的工作只是给组件的DataMember属性赋上值即可,如图: 这里CustomTableInfo表示数据集中的表名DefinedTime表示字段名。 还有一个例子,是这样的,我们经常需要在我们的软件里加上配置功能,可能这些信息是用户的操作习惯,也可能是数据库连接信息,或者是别的其它信息。这些配置功能用途很广,操作起来也不太麻烦,但如果这些配置多了,也是需要不少工作量的。在这种情况下,我们也可以使用组件来完成,假设我们要实现如右图所示的配置窗口:
我们就可以这样来设计属性 : 我们把每一个配置的相关信息设计好,具体的界面显示和数据存储都可以交给系统来完成,这样即避免了编写代码可能带来的错误和工作量,又可以保持界面的高度一致性,还是值得去做的。
给二次开发提供方便 组件的一个显著的特点就是比较容易定制自己的方法和事件,特别是事件,有很广泛的应用。在这里我和大家探讨一种处理不确定业务逻辑的方法 :
如下图,这是一个增强的datagrid的截图 它的品号列是一个比较特殊的列,列的类型是PopFormColumn,也就是可以通过点击旁边的按钮来弹出一个窗口,如图:
但有些时候我们不一定是让它弹出这个窗口,我们可能在用户点击这个按钮时发送一封邮件,也可能是别的不能在设计组件时就考虑到的操作。这个时候我们就可以使用事件来完成;但有些时候我们不一定是让它弹出这个窗口,我们可能在用户点击这个按钮时发送一封邮件,也可能是别的不能在设计组件时就考虑到的操作。这个时候我们就可以使用事件来完成; 比如我们给那个增强的grid定义一个新的事件,叫OnCreatePopColumns,它返回一个PopFormColumn对象。在grid创建弹出窗口列的时候触发;如果没有事件处理程序的话,它自己创建默认的弹出窗口列,否则就把返回的对象作为本来它应该创建的对象。这样,程序员在设计OnCreatePopColumns的事件处理程序时,就可以根据实际业务情况,从PopFormColumn继承出自己需要的对象,并做相应的处理。 这里面的关键点是:我们的组件自己能够处理大部分可以预见的业务情况,只对那些不可遇见的业务情况才需要设计事件处理程序,这样,即使业务逻辑在我们的预料之外,我们还是可以使用我们组件提供的很多功能。 除了返回这些业务逻辑相关对象以外,通过事件返回数据集也是一个很有意思的地方,它也适用在和这个类似的情况下。 总之,使用这种方法,可以解决很多不确定业务逻辑的情况,使组件的使用范围大大拓展。
使用可视化界面进行组件的属性设置 在我们开发的组件中,有相当一部分的属性设置是很复杂的,但如果使用写代码的方法来设计属性的话,可能就简单一些;不过,我还是不推荐使用代码的方式来设置属性,我认为最好的方法还是通过可视化的属性编辑器来进行属性设置 。 我们下面也通过一个例子来探讨一下:
例如,有这样一个窗口 大家可以想一下,如果通过代码来写的话,需要多少代码才可以设计出这样一个窗口呢? 但如果使用可视化属性设置的话,只需要几分钟时间就可以设计好了。 下图是那个组件的属性设置界面:
这样,通过这些属性设置就设计出了上面运行界面中的查询窗口。这样,通过这些属性设置就设计出了上面运行界面中的查询窗口。 我们可以看到,使用可视化属性设计界面可以大量节省程序员的代码量,并且提供高度一致的运行界面,也大大降低了程序设计的难度,使我们可以把更多的精力投入到业务逻辑的处理上去。当然,设计可视化属性设计器也是有一定的难度的,关于这方面的详细情况我们可以以后再讨论,重要的是使用这种思想
System.Windows.Forms.ControlPaint 这个是一个非常简单的技巧,虽然我们平时几乎不用,但在组件设计中,用处还是蛮多的。这个命名空间提供了绝大部分windows控件绘制的方法,基本上我们常见的windows控件全可以用它非常简单的绘制出来,具体细节大家看一下帮助就明白了,这里只是简单提起一下而已
组件功能最大化,可通过开关属性控制 组件最重要的特点就是重用,因此我们设计组件时,要好好规划一下组件需要完成的功能,把可以在一个组件中完成的功能尽量都集中起来。当然,有些功能在某些情况下是没有用的,这个时候我们应该能够根据实际情况来屏蔽这些功能。一个比较常用的方法是这样的,就是在这个组件里完成一个最大功能集合,然后使用一些属性来作为这些功能的开关
给大家举一个例子,如下图 这个网格控件是从System.Windows.Forms.DataGrid继承过来的,在大家通常的感觉中,DataGrid控件不好用,功能不强;但是,如果我们把这个DataGrid增强一下功能的话,还是很好用的。在这里我们给它增加了很多功能 :
行序号显示 • 可以通过右键菜单选择要显示的列 • 支持列拖放 • 各种列类型(下拉列表、选择框、时间选择、弹出窗口等等很多)的支持 • 自动记录列宽、列顺序、某列是否显示等信息 • 自动生成关联查找窗口 • 末列宽度自动调整 • … 当然,还提供了很多事件可以处理,通过这些事件可以更精确的控制网格,比如我们就可以处理某一个网格的双击事件。
通过这些功能增强,使组件的适用范围扩大了很多,当然有些时候我们可能不需要某些功能,比如我们可能不需要调节列的顺序或者不需要记录列的信息,我们就可以通过几个布尔型的属性来控制这些功能的开关。这样,我们常用的一些需求基本也就可以满足了,而通过属性的控制,可以让组件更贴近我们的需求 上面是对一个组件进行功能增强的情况,还有一种情况,就是多个组件组合成更强功能组件的情况,具体来说就是把许多功能相关的组件组合成一个大组件,并且为这些子组件提供默认的处理程序,如图
上图是一个组件,它包括了数据操作的常用按钮,并且对每一个按钮都内置了默认操作方法。我们在不写任何程序的情况下,就可以对默认关联的数据集完成新增、删除、查找、打印、关闭窗口等操作。即使对与保存,我们也只需要写很少的几行代码就可以完成。当然,对与每一个按钮我们都预留了事件处理接口,可以自己写程序处理这些事件。由于一些窗口可能不需要打印、属性、自定义这些按钮,我们也可以通过属性设置来屏蔽或隐藏这些按钮,如下图 这是把多个组件组合成一个功能增强的组件,并可以通过属性控制的情况,我们更多的时候处理的就是这种情况。
组件形成系列化,易于协作 在软件开发中,如果仅仅为了业务需要只开发出几个组件,那么这些组件带来的好处也很有限,更好的进行快速开发的方法是让组件形成系列,通过多个组件进行协作,共同完成一个复杂的业务过程
下图是一个简单的主从表窗体的例子,大家可以看到里面用到了很多组件,而这些所有的组件全是我们自己设计的,也就是说没有一个组件是标准的.net组件:下图是一个简单的主从表窗体的例子,大家可以看到里面用到了很多组件,而这些所有的组件全是我们自己设计的,也就是说没有一个组件是标准的.net组件:
我们可以看一下这些组件是怎么配合的: 很显然,窗体最上部那些组件是用来显示主表数据的,中间的是用来显示明细数据的,最下面的数据主控组件是用来控制处理数据的,还有两个查找窗口组件,是用来显示弹出的查找窗口的。 首先,那些需要和数据绑定的组件都实现了IDataMember接口;数据主控组件可以用来得到要处理的数据集,它本身还包括一个自动绑定组件,该组件可以把窗体上所有需要绑定的组件(该组件必须实现了IDataMember接口)都绑定到合适的数据集上去。数据主控组件还可以和查找窗口组件象配合,在需要查找数据时,让查找窗口组件完成查找窗体的界面显示,它本身则提供查找的数据。当然,在默认情况下,数据主控组件是和网格控件配合进行查找的,它从网格取出列信息,构造查找界面,并从自身的数据集中根据用户的要求进行查找。数据主控控件还和后台数据处理组件配合,把数据的更改传送到数据处理组件,让它自动完成数据的存储。 由此可见,要想真正提高组件式开发的效率的话,必须提供出一套互相紧密配合的组件,让这些组件本身进行自动交互。当然,开发出这套组件本身就是一个负责的工程,但当我们完成它后,就可以给我们的开发工作带来很大的便利。
交流方式 • 青岛微软开发者俱乐部(www.qddn.net) • blog(http://blog.csdn.net/tashanzhishi/) • msn(zl3624@hotmail.com)