SmartBinding实现DataSet与ListView的绑定及同步显示
kbmMW 5.10.20发布了,这个版本解决了我提出的问题,当对DataSet增删记录时,ListView能够同步显示。下面看看具体的实现代码。
为了解决上面的问题,作者为IkbmMWBindingNavigator接口增加了下面的方法:
IkbmMWBindingNavigator = interface ...... function Delete:boolean; function Insert:boolean; overload; function Insert(const ANames:array of string; const AValues:array of TValue):boolean; overload; function Append:boolean; overload; function Append(const ANames:array of string; const AValues:array of TValue):boolean; overload; procedure Refresh; property Value[const AName:string]:TValue read GetValue write SetValue; end;
通过上面的方法,即可实现对数据集的增加、删除等操作。
接下来看一下具体的实现过程:
第一步,绑定DataSet与ListView并取得返回的接口IkbmMWBinding。通过IkbmMWBinding接口的属性Navigator,可以访问IkbmMWBindingNavigator接口,从而调用上面新增的方法。
procedure TForm1.Button9Click(Sender: TObject); begin bnd:=nil; Binding.Clear; //ListView1.Items.Clear; dataset:=mt; dataset.disableControls;//kbmMW 5.10.10必须调用,kbmMW 5.10.20可以不调用了,这是改进的地方 bnd:=Binding.Bind(dataset,'f1',Edit1,'Text',[mwboTwoWay]); Binding.Bind(dataset,'f2',Edit2,'Text',[mwboTwoWay]); Binding.Bind(dataset,'f3',DateEdit1,'Date',[mwboTwoWay]); bnd:= Binding.Bind(dataset,'f1',ListView1,'#Text1'); Binding.Bind(dataset,'f2',ListView1,'#Text2'); Binding.Bind(dataset,'f3',ListView1,'#Text3'); Binding.Bind(dataset,'@',ListView1,'@',[mwboTwoWay]); dataset.EnableControls;//kbmMW 5.10.10必须调用,kbmMW 5.10.20可以不调用了,这是改进的地方 end;
当执行这段代码后,会出现下面的结果:
ListView正确的显示了数据集的所有记录内容。无论我们是执行dataset.Next还是bnd.Navigator.Next,ListView与dataSet都会同步显示当前记录的位置。
第二步,实现删除
现在我们删除一条记录:
procedure TForm1.Button12Click(Sender: TObject); begin // mt.Delete; // bnd.Navigator.Refresh; bnd.Navigator.Delete; end;
如果直接操作数据集,执行Delete方法,那么,还需要执行bnd.Navigator.Refresh;
如果直接通过bnd执行Delete方法,则不需要执行Refresh方法。
第三步,实现增加
procedure TForm1.Button11Click(Sender: TObject); begin // mt.Append; // mt.FieldByName('f1').Value:='101'; // mt.FieldByName('f2').Value:=101; // mt.Post; // // bnd.Navigator.Refresh; bnd.Navigator.Append; bnd.Navigator.Value['f1']:='101'; bnd.Navigator.Value['f2']:=101; bnd.Navigator.Value['f3']:=Date; end;
上面代码,象删除操作一样,可以通过数据集实现,也可以通过bnd接口实现。当通过数据集实现时,需要调用Refresh方法。
这里有个bug,kbmMW 5.10.10就存在,现在5.10.20还没有修复,下面是我修改的代码:
procedure TkbmMWBindingDatasetNavigator.SetValue(const AName:string; const AValue:TValue); var fld:TField; begin if IsValid then begin fld:=FDataset.FindField(AName); if fld<>nil then begin if not (FDataset.State in [dsEdit,dsInsert]) then//+++++ FDataset.Edit; //+++++ fld.AsVariant:=TkbmMWRTTI.ConvertValue2Variant(AValue,nil); end; end; end;
这是个小问题,就是FDataSet没在编辑状态。
5.10.10,需要这样调用:就是退出当前界面时,要清空bnd接口变量,让Binding能够正确的释放,不然,退出应用时会产生AV错误。
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin bnd:=nil; Binding.Clear; end;
kbmMW 5.10.20,SmartBinding绑定TDataSet与TListView,对我来说,是一个质的飞跃!可以实用到项目中了。
当然,在具体使用时,还会遇到一些问题,需要自己来处理,比如,用TDateEdit绑定一个TField,当在TDateEdit中输入日期,会产生错误,
原因就是SmartBinding是即时转换输入值到对应的TField,而这时候,还没有完整的输入一个日期。可以用下面的代码来处理:
procedure TForm1.DateEdit1Enter(Sender: TObject); begin Binding.EnableByName('DateEdit1',False);//进入这个控件时,暂时屏蔽绑定 end; procedure TForm1.DateEdit1Exit(Sender: TObject); begin Binding.EnableByName('DateEdit1',True);//退出时打开绑定 end;
上面只是我暂时想到的办法,也不太尽人意,但总算避免了出错。类似的控件还会有这样的问题,一时间想不出更好的办法。
查看kbmMW 5.10.20的更新日志,对SmartBinding框架,为TkbmMWScheduler增加了Start, Stop 及 Shutdown 方法,为TkbmMWBindings增加了Shutdown方法,通过Binding.Shutdown调用,TkbmMWEvents也增加了Shutdown方法,退出应用时作者建议我们调用以保证程序更好的退出。