红鱼儿

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

开始之前,可以复习一下kbmMWSmartBind实现ListView绑定数据集进阶篇(三)

在这篇文章中,我分享了如何将ClientQuery与Listview绑定,以及遇到的问题的解决方法,但并不完美,还存在问题。

那最好的实现方案应该是这样的:

  1. 绑定代码只执行一次
  2. 支持ClientQuery重复打开
  3. 有最好的效率
  4. 支持跨平台,比如android
  5. 不用在设计期设计好字段列表
  6. 界面与逻辑分离

现在,基于kbmMW 5.12来看看如何实现?

第一步,声明绑定对象并建立实例以及对象的销毁

  private
    FNavigatorZC:IkbmMWBinding;
    FBindOrderZC:TkbmMWBindings;

procedure TMyFrame.AfterConstruction;
begin
  inherited;
  FBindOrderZC:=TkbmMWBindings.Create;

end;

procedure TMyFrame.BeforeDestruction;
begin
  inherited;
  FNavigatorZC:=nil;
  FBindOrderZC.Shutdown;
  FBindOrderZC.DisposeOf;
end;

因为我用的Frame类,所以必须在 AfterConstruction建立以及在BeforeDestruction中销毁。

第二步,建立一个绑定方法,实现具体的绑定。

procedure TMyFrame.Binding;
begin
  if FNavigatorZC=nil then
  begin
       FNavigatorZC:=FBindOrderZC.Bind(TCpzsInfo(DataInfo).qOrderZC, 'fsn', ListView1, '#fsn');//必须在这一行取得FNavigatorZC
       FBindOrderZC.Bind(qOrderZC, 'FDate',         ListView1, '#fdate');
       FBindOrderZC.Bind(qOrderZC, 'FTruckName',    ListView1, '#ftruckname');
       FBindOrderZC.Bind(qOrderZC, 'FcustomerName', ListView1, '#fcustomername');
       FBindOrderZC.Bind(qOrderZC, 'FUserName',     ListView1, '#fusername');
       FBindOrderZC.Bind(qOrderZC, 'FState',        ListView1, '#fstate');
       FBindOrderZC.Bind(qOrderZC, 'FID',           ListView1, '#fid');
       FBindOrderZC.Bind(qOrderZC, '@',             ListView1, '@', [mwboTwoWay]);
  end;
  FNavigatorZC.Navigator.Refresh;
  FNavigatorZC.Navigator.Refresh;//这要执行两次,不然可能会显示不正确

end;

通过代码,可以看到,利用FNavigatorZC来避免重复绑定。

第三步,打开数据集,并执行Binding方法,进行绑定

procedure TMyFrame.QueryOrderZC;
begin
  qOrderZC.DisableControls;
  try
      qOrderZC.AutoFieldDefsOnOpen:=mwafoOnce;//只取一次字段定义
      qOrderZC.Close;
      qOrderZC.Query.Text:='select * from OrderZC where FState=0';
      qOrderZC.Open;
      qOrderZC.Fields.LifeCycles:= [lcPersistent];//持久化字段定义,避免重建字段
  finally
      qOrderZC.EnableControls;
  end;
end;

第四步,执行绑定

...
QueryOrderZC;
Binding;
...

上面的两行代码是可以重复执行的,所以说,支持ClientQuery的重复打开。

好了,本文章中所有代码都是实际项目提练出来,并经过生产验证,你可以放心按这个方式去使用。

2020-06-04:补充内容:

遇到按上面思路实现后,在一个功能中,有一个Listview显示不正常,第一次打开数据集显示正常,第二次数据集的sql变了,内容也变了,这时候Listview在android下不能同步显示,但是在win32下是正常的,百思不得期解。最后发现原因,原来在bind方法中为FNavigatorZC赋值的位置不对,FNavigatorZC在绑定同步位置时取得的,改到第一行,在绑定具体字段与Text对象时取得。

错误的写法是这样的:

procedure TMyFrame.Binding;
begin
  if FNavigatorZC=nil then
  begin
       FBindOrderZC.Bind(TCpzsInfo(DataInfo).qOrderZC, 'fsn', ListView1, '#fsn');
       FBindOrderZC.Bind(qOrderZC, 'FDate',         ListView1, '#fdate');
       FBindOrderZC.Bind(qOrderZC, 'FTruckName',    ListView1, '#ftruckname');
       FBindOrderZC.Bind(qOrderZC, 'FcustomerName', ListView1, '#fcustomername');
       FBindOrderZC.Bind(qOrderZC, 'FUserName',     ListView1, '#fusername');
       FBindOrderZC.Bind(qOrderZC, 'FState',        ListView1, '#fstate');
       FBindOrderZC.Bind(qOrderZC, 'FID',           ListView1, '#fid');
       FNavigatorZC:=FBindOrderZC.Bind(qOrderZC, '@',ListView1, '@', [mwboTwoWay]);//这是错误的写法,造成Listview在android下不能同步显示,win下正常。
  end;
  FNavigatorZC.Navigator.Refresh;
  FNavigatorZC.Navigator.Refresh;//这要执行两次,不然可能会显示不正确

end;

2020-06-12 在生产现场应用这些天,app工作正常!用户反应,界面显示效率比以前快多了! 实践证明上面调用方法可行。

2020-10-06 作者将在5.12的下一版本中,解决当AutoFieldDefsOnOpen:=mwafoOnce时,不再每次Open时,重建字段的问题。对于5.12及以前的版本,用以下代码修正:

procedure TkbmMWCustomPooledDataSet.InternalCreateFieldsOnOpen;
begin
   inherited;
   if AutoFieldDefsOnOpen=mwafoOnce then//+++++++
      Fields.LifeCycles:=[lcPersistent];          //+++++++
end;

 

posted on 2020-06-03 11:19  红鱼儿  阅读(411)  评论(0编辑  收藏  举报