kbmMWSmartBind实现ListView绑定数据集进阶篇(四)
开始之前,可以复习一下kbmMWSmartBind实现ListView绑定数据集进阶篇(三)
在这篇文章中,我分享了如何将ClientQuery与Listview绑定,以及遇到的问题的解决方法,但并不完美,还存在问题。
那最好的实现方案应该是这样的:
- 绑定代码只执行一次
- 支持ClientQuery重复打开
- 有最好的效率
- 支持跨平台,比如android
- 不用在设计期设计好字段列表
- 界面与逻辑分离
现在,基于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;