前文写过进阶篇一,实现了绑定后,如何重画Listview的Item。接下来,我们看看在实际项目中,如何应付各种坑?
第一个坑,关于绑定控制时间点,即在什么时候进行绑定。
在进阶篇一中,我们用的MemTable,是感觉不到这一点的。大家知道,在实际项目中,常常用TClientQuery做查询并得到数据集,这时候你每做一次查询,ClientQuery都会关闭再打开,并且重建TField对象,如果你绑定的时间点不对,会造成各种错误。先看一下我测试通过的代码实现:
FBindOrder.UpdateEvent.Activate(False);//停止绑定的同步更新 FBindOrder.Clear;//这里清空绑定的内容 Scheduler.Run( procedure(const AScheduledEvent: IkbmMWScheduledEvent) begin .... ClientQuery.Open;//执行查询 end).SynchronizedAfterRun( procedure(const AScheduledEvent: IkbmMWScheduledEvent) begin FBindOrder.Bind(ClientQuery,'FSN',ListView1,'#fsn').ToDestinationExpression('"业务单号:"+data'); ...... FBindOrder.UpdateEvent.Activate;//开始绑定的同步更新 end).WhenException( procedure(const AException: Exception) begin ApplicationShowException(AException); end).Activate;
经过这样的绑定,重复执行这段代码时,Smartbind工作正常。总结来说,当一个ClientQuery在打开前,一定要清空原有的绑定,打开后,再重新进行绑定。为什么呢?是因为FBindOrder.Bind方法,会把数据集的字段对象与界面对象加入FBindOrder内部的列表中,并按这个列表进行更新,当关闭ClientQuery再重新Open,数据集的字段对象会重建,已经不再是原来的对象,而FBindOrder内部的列表中的对象已经不存在了,所以必须重新进行绑定。进一步补充,当你做绑定时,一定在数据集打开后,才能进行绑定操作。
第二个坑,小心绑定的异步执行。
前文有写过,SmartBind的工作原理,是利用一个调度对象,默认情况下每100毫秒同步数据源(数据集)与目标源(界面控件)。因为是定时同步,所以必须理解为异步执行的。我们看一下,异步执行带来的问题,先看一下代码:
var FBindGoods: TkbmMWBindings; begin ...... FBindGoods := TkbmMWBindings.Create; FBindGoods.Clear; ClientQueryGoods.Open FBindGoods.Bind(ClientQueryGoods, 'FName', Edit1, 'Text'); ...... Edit1.Text:='宝马X6'; ShowMessage(ClientQueryGoods.FieldByName('FName').AsString); ......
上面代码,我们将一个字段与Edit1.Text绑定,然后操作Edit1.Text,再调用ShowMessage显示字段的内容,结果是ShowMessage不会显示“宝马X6”。原因就是SmartBind还没有执行更新动作,将Edit1.Text内容写进字段。这种代码场景,一定要记住,避免异步带给我们的影响。
换句话说,当你改变数据源或目标源时,因为异步的原因,不能同时更新数据源或目标源,因此,当你更新数据源或目标源后立即从对应的数据源或目标源取得数据,是取不到正确的值的。这不仅影响数据源或目标源的值,同样也影响数据源或目标源的位置。比如,将DataSet与ListView做双向绑定,当你在ListView中选择一行,然后立即从DataSet当前记录中取值,取到的结果将是错误的。
第三个坑,绑定对象的释放。
SmartBind为我们提供了全局对象Binding,在实际项目中,是不实用的,还需要我们自己来建立与释放kbmMWBindings。以第二个坑中用到的FBindGoods为例,一定要记得自己释放他,如果在Frame中建立的绑定对象,一定要在BeforeDestruction中释放。
procedure TMyFrame.BeforeDestruction; begin bnd:=nil; FBindGoods.Shutdown; FBindGoods.DisposeOf; inherited; end;
按上面的代码释放,应用无论在何时退出,都会天下太平,否则将产生各种地址错误。