红鱼儿

kbmMWSmartBind实现ListView绑定数据集进阶篇(二)

前文写过进阶篇一,实现了绑定后,如何重画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;

按上面的代码释放,应用无论在何时退出,都会天下太平,否则将产生各种地址错误。

 

posted on 2020-04-11 15:48  红鱼儿  阅读(332)  评论(0编辑  收藏  举报