SmartBinding与kbmMW#2
前言
在之前的文章中,我介绍了SmartBinding作为Delphi的一个新的易于使用和智能的绑定框架。介绍了包括绑定对象,列表,常规数据和可视控件,以及如何使用导航器,所有这些都用代码做了演示。
本文将重点关注下一个kbmMW版本中包含的新SmartBinding功能(SmartBinding v2),预计很快就会发布。
一行代码绑定
为使kbmMW SmartBind更加智能,目的之一就是要删除所有重复的绑定代码,使开发者只关注具体的功能需求。通过代码执行SmartBinding非常简单,但为了更容易实现,请看下面的演示:
先做一个简单的Form,如上图,Form包含一个TLabel,一个TButton和两个TEdit。
试着运行它:
当在Edit3输入内容时,其余控件的Caption和Text都会自动更新。这个功能我已经在之前的SmartBinding博文中介绍过,不知你还记得不?
在之前的博文中,有许多Binding.Bind 代码行将控件绑定在一起,但在此例子中,只需要在TForm的OnCreate事件中用一行绑定代码:
Binding.AutoBind(self);
怎么可能?!现在的kbmMW SmartBinding能够检查对象和控件的String属性,以获取绑定指令。
Label.Caption属性中可以清楚地看到一个绑定指令:{Edit3.Text}
只需将绑定内容放在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来包含绑定数组,所以按钮看起来不是最终用户友好的。但是,这很容易通过以下方法之一来解决:
- 不要使用TButton.Caption进行绑定,而是使用在运行时不可见的其他String属性
- 将TButton.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,我们可以看到它是一个对象(它以花括号开头和结尾),并且它包含许多定义数据生成的属性。
类型目前可以是以下之一:
- 简单
这只是静态数据。任何只有与之关联的静态数据的命名属性自动被理解为简单类型。 - number
这是一个将返回某种类型的生成器。其他属性定义如何。 - values
这是一个返回许多已定义值之一的生成器。其他属性定义如何。
如果它的编号可以使用这些附加属性:
- random:true / false
如果为true,将生成min和max之间的随机值,舍入到最近的步。
如果为false,将生成从min开始的增量值(或给定的值),并在每个循环中以步长递增。 - min:n
n是数值。设置此生成器返回的数值的下边界。 - max:n
n是数值。设置此生成器返回的数值的上边界。 - 步骤:n
n是一个数值,表示根据其是随机值还是增量值来完成的步骤或舍入。 - interval:n
n是msecs中的数值,表示值应该更改的频率,interval:250表示它最多每秒更改4次。 - 小数:n
定义后面的小数位数。回来。生成器将生成一个整数值,并将其除以10 ^ n以生成小数。默认值为0。 - wrap:true / false
如果为true且它不是随机值,则生成器将在到达边界时自动回绕。
如果为false,则在边界处达到的值将变为静态。 - reverse:true / false
如果为true,它将以相反的顺序返回数据。 - value:x x是要返回的初始值。
如果是其值,则可以使用以下附加属性:
- random:true / false
如果为true,则会随机选择一个值。
如果为false则会选择下一个值。 - 步骤:n
n是一个数值,表示根据其是随机值还是增量值来完成的步骤或舍入。 - wrap:true / false
如果为true且不是随机值,则生成器将在达到values数组的边界时自动回绕。
如果为false,则在边界处达到的值将变为静态。 - reverse:true / false
如果为true,它将以相反的顺序返回数据。 - interval:n
n是msecs中的数值,表示值应该更改的频率,interval:250表示它最多每秒更改4次。 - values:[...,...,...。]
可以为此命名属性返回的值数组。
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:=;
FVal2:='TESTING';
FVal3:=11.1;
FVal4:=22.2;
FVal5:=33.3;
FVal6:=44.4;
FVal7:=;
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:=;
line1.Val3:=1.1;
line2.Val1:='Hej 2';
// line2.Val2.IsNull:=true;
line2.Val3:=2.2;
line3.Val1:='Hej 3';
line3.Val2:=;
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,);
mt.FieldDefs.Add('Val2',ftInteger);
mt.FieldDefs.Add('Val3',ftFloat);
mt.FieldDefs.Add('Val4',ftString,);
mt.CreateTable;
mt.Open;
mt.AppendRecord(['value 1',,111.1,'value 1_2']);
mt.AppendRecord(['value 2',,222.2,'value 2_2']);
mt.AppendRecord(['value 3',,333.3,'value 3_2']);
mt.AppendRecord(['value 4',,444.4,'value 4_2']);
现在我们只需要“切换”数据而不是基于TLines的数据。“重新定义test2数据”的事件处理程序如下所示:
Binding.DefineData('test2',mt);
单击它,屏幕将立即如下所示:
以前链接到FLines实例的所有绑定现在已重新链接到内存表实例,我们可以继续单击Prev和Next来滚动数据。
还有什么?
除了上述自动绑定功能,它还支持使用kbmMW中许多其他地方支持的$(configpath)语法从配置框架中获取数据,SmartBinding v2还包括:
- 支持kbmMWNullable类型
- GroupedBy(..),NamedBy(..)绑定方法,可用于识别和操作绑定。在基于字符串的自动绑定中,将组作为组提供:“groupname”和名称作为名称:“bindingname”。可以有多个具有相同名称和组的绑定。
- 通过公共单例BindingGeneratorRegistrations进行自定义绑定数据生成器注册
- 改进了对焦控制的检测,以便在打字时处理双向绑定,更加优雅。
- 过程UnbindBindings(const ABindings:TList <IkbmMWBinding>);
一次取消绑定绑定列表 - procedure EnableBindings(const ABindings:TList <IkbmMWBinding>; const AEnable:boolean);
一次启用或禁用绑定列表 - procedure UnbindByGroup(const AGroup:string);
取消绑定基于组名的绑定。 - procedure UnbindByName(const AName:string);
取消绑定基于绑定名称的绑定。 - procedure EnableByGroup(const AGroup:string; const AEnable:boolean);
根据组名启用/禁用绑定。 - procedure EnableByName(const AName:string; const AEnable:boolean);
根据绑定名称启用/禁用绑定。 - function BindingsByGroup(const AGroup:string):TList <IkbmMWBinding>;
根据组名返回绑定列表。 - function BindingsByName(const AName:string):TList <IkbmMWBinding>;
根据绑定名称返回绑定列表。
结束语
通过轻松支持绑定和数据分离,可以更轻松地完成功能模型(提供服务器和GUI应用程序的数据),只需轻轻一按开关即可将其转换为生产代码。
它可以以多种方式使用。一种方法是能够通过绑定到来自生成器的简单静态文本集,或者通过创建新的自定义翻译生成器来自动翻译GUI上的所有文本,您可以在其中选择当前语言,因此返回显示以及如何(控件的大小和位置可以以相同的方式绑定)。
自动绑定将锅炉板编码减少到绝对最小值,同时仍然满足简单重构GUI的要求,只是因为大多数情况下的绑定定义将遵循特定控件,只要在其中一个控件中定义绑定即可字符串属性。在其他控件(可视或非可见)字符串属性中定义绑定的情况下,您至少不会通过简单地重构控件来松散绑定定义。
它可以轻松访问加载和保存文件的绑定,以处理非常晚的绑定,这可以在安装时用于非常动态的应用程序客户专业化,而不是编译。
SmartBinding与kbmMW#2的更多相关文章
- SmartBinding与kbmMW#1
即将发布的kbmMW,实现了SmartBinding,SmartBinding的设计目标是: 必须易于使用 必须最小化或完全删除锅炉板代码.(你看到这里的趋势了吗?... kbmMW从那时开始就是为了 ...
- SmartBinding with kbmMW #4
前言 在前面写过的文章中,详细介绍过如何将各种的控件与数据源进行绑定(Bind).在这篇文章中,将重点讨论如何绑定TImage和TListView.(同时支持VCL与Firemonkey). 将图形数 ...
- SmartBinding与kbmMW#3
前言 在SmartBinding #2中,我介绍了新的自动绑定功能,支持在Form设计器中直接定义绑定.不仅如此,kbmMW SmartBind还有更多很酷的功能,即将发布的kbmMW中的SmartB ...
- kbmMW 5.09测试报告(1)-Scheduler
这个版本除了增加新的SmartBinding功能,同时提供了大量的功能更新以及bug修正.其中,SmartBinding的介绍,xalion已经第一时间写了初识kbmmw 中的smartbind功能, ...
- kbmMW 5.10.10 SmartBinding问题修正
千呼万唤始出来,最新的kbmMW 5.10.01终于发布了,详情可以看xalion发的更新日志. 我期待的Smartbinding for Listview终于来了,在这一版本中,对SmartBind ...
- SmartBinding实现DataSet与ListView的绑定及同步显示
kbmMW 5.10.10发布了,这个版本解决了我提出的问题,当对DataSet增删记录时,ListView能够同步显示.下面看看具体的实现代码. 为了解决上面的问题,作者为IkbmMWBinding ...
- SmartEvent with kbmMW #1
前言 前面的文章,我写了有关SmartBinding框架方面的内容.SmartBinding的目的是将数据容器绑定到一起,通常情况下,数据容器可以是显示数据或与数据交互的控件(Edit,ListVie ...
- kbmMW 5.10.01试用报告
1.FileClient.SameFile 调用这个方法,当本地文件不存在时,会一直等待.跟踪代码,发现: function TkbmMWCustomFileClient.SameFileEx(Loc ...
- SmartBinding工作原理分析
关于kbmMW SmartBinding,我翻译了作者写的几篇文章,其强大的绑定机制,将可视控制与各种数据源灵活绑定在一起,实现了类似DBEdit数据敏感控件的效果,可以及大的减少我们的代码,实现界面 ...
随机推荐
- [spring mvc][转]<mvc:default-servlet-handler/>的作用
优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...
- syslog+rsyslog+logstash+elasticsearch+kibana搭建日志收集
最近rancher平台上docker日志收集捣腾挺久的,尤其在配置上,特写下记录 Unix/Linux系统中的大部分日志都是通过一种叫做syslog的机制产生和维护的.syslog是一种标准的协议,分 ...
- 一百二十二:CMS系统之页面抽离和登录页面
将登录和注册需要的共性标签抽离出来做父模板 将css改名为base base模板 {% from 'common/_macros.html' import static %}<!DOCTYPE ...
- UIView和UIWindow的使用
1.创建窗口: func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [N ...
- AssetBundle资源打包与加载
AssetBundle资源打包 1.AssetLabels资源标签 文件名:资源打包成AssetBundle后的文件名,类似于压缩包的名字 后缀:自定义 文件名和后缀名都是小写格式(大写会自动转为小 ...
- CenterNet算法笔记(目标检测论文)
论文名称:CenterNet: Keypoint Triplets for Object Detectiontection 论文链接:https://arxiv.org/abs/1904.08189 ...
- 【C/C++开发】__stdcall,__cdecl,__fastcall的区别
__stdcall和__cdecl的区别 __stdcall和__cdecl是两种函数名字修饰.(注意是连续的两个下划线) Windows上 windows上不管是C还是C++,默认使用的都是__st ...
- mongodb base
数据库,集合(表),文档(行) 嵌入式关系 引用式关系
- day29 元类及异常处理
元类及异常处理 元类 什么是元类 在python中,一切皆对象,对象是由类产生的,那么类是不是对象呢? 举例: class A: pass print(type(A)) # <class 'ty ...
- 在win7下安装PowerShell 5.0遇到的坑
升级安装 安装.NET Framework 4.6.2下载NDP462-KB3151800-x86-x64-AllOS-ENU.exe,进行安装 安装PowerShell 4.0(5.0依赖4.0) ...