在以前的文章中,我介绍了SmartBinding做为Delphi的一个新的易于使用和智能的绑定框架。介绍了包括绑定对象,列表,常规数据和可视控件,以及如何使用导航器,全部这些都用代码作了演示。html
本文将重点关注下一个kbmMW版本中包含的新SmartBinding功能(SmartBinding v2),预计很快就会发布。数据库
为使kbmMW SmartBind更加智能,目的之一就是要删除全部重复的绑定代码,使开发者只关注具体的功能需求。经过代码执行SmartBinding很是简单,但为了更容易实现,请看下面的演示:
express
先作一个简单的Form,如上图,Form包含一个TLabel,一个TButton和两个TEdit。数组
试着运行它:服务器
当在Edit3输入内容时,其他控件的Caption和Text都会自动更新。这个功能我已经在以前的SmartBinding博文中介绍过,不知你还记得不?框架
在以前的博文中,有许多Binding.Bind 代码行将控件绑定在一块儿,但在此例子中,只须要在TForm的OnCreate事件中用一行绑定代码:dom
Binding.AutoBind(self);
怎么可能?!如今的kbmMW SmartBinding可以检查对象和控件的String属性,以获取绑定指令。编码
Label.Caption属性中能够清楚地看到一个绑定指令:{Edit3.Text}spa
只需将绑定内容放在Label.Caption中,Label就会与控件Edit3.Text属性绑定,来接收数据。按钮的绑定方式与Edit3相同。第二个TEdit也绑定到Edit3,但在这里进行了双向绑定:{Edit3.Text,twoway:true}翻译
总之,你如今能够直观地看到控件从哪里获取可视数据。
如今咱们看看Demo应用程序的第二页:
这显示了如何在一个String属性中指定多个绑定。TButton控件的Caption属性如今设置了一个包含2个绑定的数组,一个是Edit1.Text绑定到Label2.Caption,另外一个是Edit1.Text绑定到Label1.Caption。键入Edit1将按预期更新两个Label。
你可能已经注意到,由于咱们使用按钮的Caption来包含绑定数组,因此按钮看起来不是最终用户友好的。可是,这很容易经过如下方法之一来解决:
值语法就象下面这样定义绑定:
[{value:"Button"},{bind:Edit1.Text, to:Label2.Caption}, { bind: Edit1.Text, to: Label1.Caption}]
运行后的结果:
象值语法这样的方式,使用常量字符串做为值,使得Button如今有一个正常的标题了,但也可使用kbmMW配置框架,具体请参阅有关kbmMW配置管理器的博文。
经过将exprToSrc:“expression”和/或exprToDest:“expression”字符串属性添加到相关绑定部分,也能够指定目标和源表达式。经过设置disabled:true,能够将绑定设置为默认禁用。
若是可以在设置任何真实数据以前设计GUI,那不是很好吗?换句话说,可以开发实时模型,而且能够经过开关来转换为实际应用程序。
这就是绑定/数据分离发挥做用的地方,如今咱们来看Demo的第三页:
在这个页面上,有8个Label,其中7个看起来像是对它们有特定的意义的设置。
经过使用@语法,我告诉kbmMW SmartBinding它应该与名为test的数据占位符绑定。
让咱们运行它:
发生了什么?在实时系统中,您将看到绑定从@test获取数据。@Test.Value2和@ test.Value3填充了静态数据,而其他的绑定产生了看似随机的数据。这是来自kbmMW的SmartBinding数据生成器的数据示例。
在调用AutoBind以前的某个地方,咱们必须定义可能正在使用的数据占位符。
var data:IkbmMWBindingData; begin data:=TkbmMWBindingDataGenerator.Create('{'+ ' value1:10,'+ ' value2:"abc",'+ ' value3:88.4,'+ ' value4: &random {'+ ' type:number,'+ ' random:true,'+ ' min:10000,'+ ' max:100000,'+ ' step:5,'+ ' interval:250'+ ' },'+ ' value5: *random,'+ ' value6: *random,'+ ' value7: *random,'+ ' value8: {'+ ' type: values,'+ ' random: true,'+ ' values: ["AAA","BBB","CCC","DDD","EEE"]'+ ' }'+ '}'); Binding.DefineData('test',data); Binding.AutoBind(self); end;
经过调用DefineData,咱们在名称'test'和将生成并接受绑定数据的东西之间创建了一个连接,在这种状况下,绑定是TkbmMWBindingDataGenerator的一个实例data。
它接受一个字符串,其中包含简化的YAML,描述了该生成器应为其生成数据的各类命名属性。每一个命名属性能够是常量值,如value1,value2和value3,也能够是描述如何生成特定命名属性的数据的对象。
看看value4,咱们能够看到它是一个对象(它以花括号开头和结尾),而且它包含许多定义数据生成的属性。
类型目前能够是如下之一:
若是它的编号可使用这些附加属性:
若是是其值,则可使用如下附加属性:
kbmMW支持添加其余自定义数据生成器类型。
咱们使用命名属性value4看到的一个特殊语法是YAML锚点(&random)。定义时,其余命名属性值可使用* random语法引用相同的定义。这就是为何value5,6和7都返回随机值的缘由。
因此如今咱们了解如何定义数据生成器。可是如何在开发过程当中使用真实数据替换数据生成器?
很简单。例如。
type TTest = class private FVal1:kbmMWNullable<integer>; FVal2:kbmMWNullable<string>; FVal3:kbmMWNullable<double>; FVal4:kbmMWNullable<double>; FVal5:kbmMWNullable<double>; FVal6:kbmMWNullable<double>; FVal7:kbmMWNullable<integer>; FVal8:kbmMWNullable<string>; public constructor Create; property Value1:kbmMWNullable<integer> read FVal1 write FVal1; property Value2:kbmMWNullable<string> read FVal2 write FVal2; property Value3:kbmMWNullable<double> read FVal3 write FVal3; property Value4:kbmMWNullable<double> read FVal4 write FVal4; property Value5:kbmMWNullable<double> read FVal5 write FVal5; property Value6:kbmMWNullable<double> read FVal6 write FVal6; property Value7:kbmMWNullable<integer> read FVal7 write FVal7; property Value8:kbmMWNullable<string> read FVal8 write FVal8; end; ... constructor TTest.Create; begin inherited; FVal1:=21; FVal2:='TESTING'; FVal3:=11.1; FVal4:=22.2; FVal5:=33.3; FVal6:=44.4; FVal7:=55; FVal8:='TESTING more!'; end; ... begin testdata:=TTest.Create; Binding.DefineData('test',testdata); end;
调用此代码时,咱们会动态地使用对象testdata中的数据替换数据生成器。所以,单击“Redefine test data”按钮将产生下面的运行结果:
所以,咱们如今已经展现了真正的关注点分离,这使得开发者能够独立地设计GUI及控制代码,而且能够做为团队中我的单独任务来开发数据层。
如今咱们来到Demo的最后一页。
这也是一个绑定分离的演示。
在这里,咱们将对象列表定义为初始绑定数据:
TLine = class private FVal1:kbmMWNullable<string>; FVal2:kbmMWNullable<integer>; FVal3:kbmMWNullable<double>; public property Val1:kbmMWNullable<string> read FVal1 write FVal1; property Val2:kbmMWNullable<integer> read FVal2 write FVal2; property Val3:kbmMWNullable<double> read FVal3 write FVal3; end; TLines = TObjectList<TLine>; ... FLines:=TLines.Create; ... var line1,line2,line3:TLine; begin Flines:=TLines.Create; line1:=TLine.Create; line2:=TLine.Create; line3:=TLine.Create; line1.Val1:='Hej 1'; line1.Val2:=1; line1.Val3:=1.1; line2.Val1:='Hej 2'; // line2.Val2.IsNull:=true; line2.Val3:=2.2; line3.Val1:='Hej 3'; line3.Val2:=3; line3.Val3:=3.3; Flines.Add(line1); Flines.Add(line2); Flines.Add(line3); Binding.DefineData('test2',FLines); end;
咱们(在这段代码中为了它的乐趣)将FLines数据绑定到可视控件:
Binding.Bind(Flines,'Val1',edVal1,'Text',[mwboTwoWay]).Navigator; Binding.Bind(Flines,'Val2',edVal2,'Text',[mwboTwoWay]); Binding.Bind(Flines,'Val3',edVal3,'Text',[mwboTwoWay]);
Next和Prev按钮包含如下代码:
// The Prev buttons eventhandler: var nav:IkbmMWBindingNavigator; begin nav:=Binding.GetDataNavigator('test2'); if nav<>nil then nav.Previous; end; // The Next buttons eventhandler: var nav:IkbmMWBindingNavigator; begin nav:=Binding.GetDataNavigator('test2'); if nav<>nil then nav.Next; end;
这段代码与我在第一篇博文中所展现的略有不一样,由于我没有存储绑定及其导航器以供之后使用,而是根据定义的绑定的名称在须要时请求导航器。数据。
运行它,它将像咱们习惯的那样:
咱们可使用Prev和Next按钮滚动值。
然而…。若是咱们如今想用数据库中的真实数据替换这个模型列表怎么办?
对于演示,咱们使用内存表的内容模拟数据库中的数据。
mt:=TkbmMemTable.Create(nil); mt.FieldDefs.Add('Val1',ftString,30); mt.FieldDefs.Add('Val2',ftInteger); mt.FieldDefs.Add('Val3',ftFloat); mt.FieldDefs.Add('Val4',ftString,30); mt.CreateTable; mt.Open; mt.AppendRecord(['value 1',1,111.1,'value 1_2']); mt.AppendRecord(['value 2',2,222.2,'value 2_2']); mt.AppendRecord(['value 3',3,333.3,'value 3_2']); mt.AppendRecord(['value 4',4,444.4,'value 4_2']);
如今咱们只须要“切换”数据而不是基于TLines的数据。“从新定义test2数据”的事件处理程序以下所示:
Binding.DefineData('test2',mt);
单击它,屏幕将当即以下所示:
之前连接到FLines实例的全部绑定如今已从新连接到内存表实例,咱们能够继续单击Prev和Next来滚动数据。
除了上述自动绑定功能,它还支持使用kbmMW中许多其余地方支持的$(configpath)语法从配置框架中获取数据,SmartBinding v2还包括:
经过轻松支持绑定和数据分离,能够更轻松地完成功能模型(提供服务器和GUI应用程序的数据),只需轻轻一按开关便可将其转换为生产代码。
它能够以多种方式使用。一种方法是可以经过绑定到来自生成器的简单静态文本集,或者经过建立新的自定义翻译生成器来自动翻译GUI上的全部文本,您能够在其中选择当前语言,所以返回显示以及如何(控件的大小和位置能够以相同的方式绑定)。
自动绑定将锅炉板编码减小到绝对最小值,同时仍然知足简单重构GUI的要求,只是由于大多数状况下的绑定定义将遵循特定控件,只要在其中一个控件中定义绑定便可字符串属性。在其余控件(可视或非可见)字符串属性中定义绑定的状况下,您至少不会经过简单地重构控件来松散绑定定义。
它能够轻松访问加载和保存文件的绑定,以处理很是晚的绑定,这能够在安装时用于很是动态的应用程序客户专业化,而不是编译。