关于自定义控件属性如何保存等问题的再讨论。。。

                            
   
          先说一些题外话。  
   
          ①这是我第一次尝试编写有实用价值的控件。以前我没有任何编写控件的经验,翻阅了很多书,也在网上搜索良久,可惜没有什么结果,关于控件开发的资料实在是太少了,仅仅看到一些诸如Component   Message和Component   Notify之类的极其简单的介绍,连个示例都没有。我也对这些控件消息和控件通知服务(过程)只有一点皮毛的理解。在提问(在大富翁)时,zjan521给出的示例代码中的“if   csDesigning   in   ComponentState   then”我还是第一次看到(猜测其意义是   if是在设计时期   then...   ,由此我想Delphi中应该还有很多关于如何控制控件在设计时期和运行时期不同的状态的处理或者判断方法,这些我一点都不懂)。唯一看到有一点价值的资料是《控件开发FAQ》还是台湾人翻译的,其中提到的控件开发参考资料《Developing   Delphi   Component》等都无法找到。所以,恳请各位高手能否给出一些控件开发的参考资料或实例?  
   
          ②我使用Delphi一年多,从开始时用Access作数据库,到后来转到SQL   Server上来,编程方法也逐步从单纯使用数据库控件Open、Edit、Post到使用嵌入SQL语句,而现在正尝试使用面向对象的方法来封装数据对象(OR   Mapping?)以及对数据的操作,这其中也得到一个很忙碌的高手朋友的一些启发和指导(可惜他太忙了,大部分情况下我只是听到他的只言片语,其他都是我自己琢磨)。  
          我最近编写了一个管理软件,在代码中没有用到任何SQL语句,几乎所有的数据操作都是通过封装的对象的方法来完成的。现在那软件基本已经完成投入使用了。正是因为使用了面向对象的方法,在软件设计过程中有几次大的需求改变,而我只是修改了一些类的实现方法和属性就能对付了,基本的架构没有太大的变化,这一点跟以前使用Open/Edit/Post的方法比起来工作量小得多了。总结下来,使用面向对象的方法来封装数据对象,对最基本的五个个操作CRUD(微软总结的Create,Read,Upate,Delete)和List(这是我的术语)的封装实现中,List最为麻烦。按说,采用面向对象的方法来进行数据库操作,就应该完全不使用和数据库有紧偶合的数据感知控件,如典型的DataSet(ADOTable,ADOQuery等)-》DataSource-》Grid数据感知控件等。但是,现阶段要自己实现数据的完美显示(可以分组、排序、导出等),还要在显示的基础上实现快速查找、复杂查询等派生功能,工作量实在是太大了,而且凭一己之力也不可能做得很完美。所以我在尝试使用面向对象的数据库编程时,对List的实现方法作了妥协,仍采用数据库控件的显示方式,但仅仅是用来显示(DataSet的AutoEdit属性设定为False)。另外,市面上的Grid控件种类实在是太多了,功能又炫又强,不用也实在是可惜。我为了实现通用的快速查找、复杂查询等List的各种扩展功能,才决定自己编写控件(从dxDBGrid继承),但因为我实在是写控件的新手,所以碰到N多的问题。。。。  
   
   
          考虑以下代码(派生控件的Create):  
   
  constructor   TdxDBGrid3En.Create(AOwner:   TComponent);  
  begin  
      inherited;  
   
      FDataSource:=TDataSource.Create(nil);           //注1  
      FADOSP:=TADOStoredProc.Create(Self);             //注2  
   
      //FADOSP:=TADOStoredProc.Create(AOwner);     //注3  
   
      ......  
  end;  
   
          DataSource和ADOStordProc都是非可视化控件,现在我要在我的自定义控件中使用它们。现在我们来关注Create函数的参数AOwner:Tcomponent   :  
          1.如果AOwner设定为nil,则在设计时期我拖放我自定义的控件到Form上时,以nil为参数创建的子控件就不会出现在Form上。但是也正因为Owner是nil,所以,在保存Form的时候,该控件的属性不会被保存(李维的书上说,在保存Form的时候,Delphi   IDE会根据Owner遍历每个子控件并保存每个子控件在设计时期定义的属性到dfm文件中去)。具体在我的自定义控件中,对于DataSource的Owner设为nil问题不大(DataSource我要设定的属性也就一个,在上面的构建代码中设定了,只是在这里没有写出来),但是对ADOSteodProc,问题就大了,如果Owner是nil,那么ADOStoredProc控件就不会出现在Form上,而且,在Object   Inspector中该属性是空的!我的本意是我可以在Object   Inspector中展开ADOStoredProc来指定其Connection和ProcName,并且将其Active,这样我才能在设计时期将要显示的字段添加到Grid中(然后设定Grid显示字段的各种不同属性);  
          2.如果AOwner设定为Self,在设计时期该子控件也不会出现在Form上,但是比设定为nil好一些,ADOStoredProc可以在Object   Inspector中展开并设置各种属性,也能够Active,并且Grid中能正常显示数据。但是基于同样的原因,设计时期设定的ADOStoedProc的各种属性仍不能保存到dmf中去,下次重新在IDE中加载该From时,仍必须重新设定各种属性:(!  
          3.如果AOwner设定为AOwner,那么就是说,让新建立的子控件成为其Form的子控件(新建立的子控件的Parent是Form)。这时,可以在Object   Inspector中展开ADOStoredProc并设置各种属性,也能在保存Form时将各种属性保存到dfm文件中去,但是这样做会有两方面的问题:  
                  A.第二次在IDE中加载该Form时,TdxDBGrid3En.Create再次得到执行的机会,因为第一次设计时已经有ADOStoredProc控件并设定了相关的属性,且能在第二次成功加载,TdxDBGrid3En.Create构建方法再次执行的时候会告诉我同名的控件已经存在而创建失败(且把原来控件设定的正确属性设又定错了),解决这个问题的关键是TdxDBGrid3En.Create函数中,如何判断第一次创建的控件已经存在了呢?(又是使用csDesigning   in   ComponentState吗?但是ADOStoredProc在第一次设计时期可能被改名字了)  
                  B.我编写这个控件的原意是将ADOStordProc、DataSource和dxDBGrid封装在一起形成一个控件并在该控件的基础上实现我额外的功能,现在如果AOwer设定为AOwner,那么在设计时期,一旦将我自定义的控件放到Form上,ADOStoredProc控件也会同时出现在Form上,这不符合“我只放了一个控件”的习惯,更严重的问题是,因为不该出现在Form上的ADOStoredProc出现在Form上,一不小心就可能把ADOStoredProc控件给删了,这让人很不爽。。。  
   
          综上所述,我的问题是,如何编写TdxDBGrid3En.Create构建函数,让我既可以在设计时期在Object   Inspector中设定ADOStoredProc的各种属性,并且这些设定的属性能够保存到dfm中,而且在第二次加载的时候不会出现错误;又能够不让ADOStoredProc在设计时期不出现在Form上?  
   
 

查看回复