控件间关联,Notification不能忘

 来龙去脉

最近在编写一些简单控件时,用到了控件间的关联,即一个控件属性中组合了另一个控件的实例(类似于TDataSource的DataSet属性),控件编写和运行一切顺利,但随后的设计期操作却让人不知所措。
设计期,在窗体拖放两个控件,并将其关联,如A的一个属性是B,由于delphi设计期拥有强大的即时处理能力,关联好之后,两个控件的设置立即生效。
但是,此时如果将B从窗体删除,让人不快的事情发生了,一个红叉叉对话框告诉我们,“rtl10.bpl”之类的核心出现异常,点击OK按钮,界面开始混乱,对话框不断,只能用任务管理器强行结束,貌似是致命性错误。
再次打开delphi,上述问题依旧存在,而且排除了delphi的BUG问题(已升级到最新的hotfix),因为delphi自带的关联控件(比如TDataSource和TDataSet关联)不会出现错误,那么就是我的控件在设计期出现了错误。
由于对设计期delphi的控件管理不了解,只好使用Ctrl跟踪了TfrxDBDataset的DataSet关联(TDataSource使用了特殊的关联通知方式,并结合了StateChange事件,不具通用性),发现在TfrxDBDataset中存在这样一个函数:
 
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure TfrxDBDataset.Notification(AComponent: TComponent; Operation: TOperation);
begin
 inherited;
 if Operation = opRemove then
    if AComponent = FDataSource then
      DataSource := nil
    else if AComponent = FDataSet then
      DataSet := nil
end;
 
很明显Notification是override的基类的函数,它是TComponet类型控件互动通知模式的一部分,控件互动通知模式可以使关联的控件在创建或销毁时,通过该函数通知被关联的控件。在此前编写的控件,由于没有在关联控件销毁时即时将被关联控件相关属性设为空,造成了指针失效错误,而由于是在设计期产生的,因而引发了delphi IDE的致命错误。因此,要解决上述问题,只需要重载Notification函数,在接收到opRemove(控件被移除)操作时将相关属性设为空即可。
修改完毕,再次编译、安装控件,问题解决。
经验总结
1、    VCL内部使用了诸多优秀的设计模式,并发挥了强大的作用。理清VCL的设计脉络有助于我们尽快的找到设计的不足和解决方法。
2、    VCL绝大部分都具有源代码,遇到问题时勤于跟踪现有代码,会在解决问题的基础上提高我们的设计水平。
3、    设计中出现错误时,可使用替换法缩小问题范围,用现有的正常代码与问题代码做比较,找出问题所在。

 

标签:
文章分类 FK Coding

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

点赞
如果您觉得很赞,我将非常乐意接受虚拟币的捐赠,以示您对我的肯定。

比特币钱包地址:
1PqpqA8FyH3NbfCrbcRd1YxQk3LEsSEYDV
莱特币钱包地址:
LRTdmovGGVEHCKWz7JdL9aiB7VZkuNycJf
站点勋章
网站统计