即将发布的kbmMW,实现了SmartBinding,SmartBinding的设计目标是:

  • 必须易于使用
  • 必须最小化或完全删除重复的代码。
    (你看到这里的趋势了吗?... kbmMW初心就是为了让事情变得简单!)
  • 必须有良好的表现
  • 必须具有较低的CPU占用及内存占用
  • 绝不能导致无休止的循环调用
  • 应该使用各种数据和控件
  • 应该是灵活和可扩展的
  • 必须接近实时
  • 必须易于重构
  • 应该与kbmMW的其他功能很好地配合
  • 即使不使用kbmMW的其他功能也应该可用

看一个简单的属性绑定:

简单绑定

     Binding.Bind(Edit1,'Text',Label1,'Caption');
Binding.Bind(Edit1,'Text',Button1,'Caption');
Binding.Bind(Edit1,'Text',Edit2,'Text',[mwboTwoWay]);

上面代码,在edit1中输入内容,Label1.Caption,Button1.Caption,Edit2.Text 三个组件显示的内容会跟edit1.text一模一样。第三个是双向绑定,edit2中输入内容,edit1也会更新。

Binding实例来自哪里?他是kbmMW SmartBinding默认带的一个实例,可以立即使用。代码的最后一行还包括一个可选参数mwboTwoWay,表示绑定是同步的,更改一方也会自动更新另一方。

基本上所有字符串布尔值浮点int64整数属性都可以通过自动转换轻松绑定,其中SmartBinding确保根据需要自动在不同类型之间转换数据。其他类型的数据也可以绑定,但源和目标属性必须是相同的类型(也有方法也可以...见后面)。

线程安全方面是什么情况呢?kbmMW SmartBinding自动识别从TControl类的继承的组件,所以它必须在主线程中执行更新,才保证应用程序稳定运行。

接下来,我们看看Record的绑定:

绑定Record

kbmMW SmartBinding实现绑定到常规对象或者Record,只要确保数据始终可用,那绑定就存在。如果数据不存在了,可以使用kbmMW SmartBinding实现的解绑与重新绑定功能。下面的代码,实现TEdit与全局Record的绑定:

type
TData = record
FData1:string;
end; var
data:TData;
...
Binding.Bind(Edit1,'Text',@data,TypeInfo(TData),'FData1');
Binding.Bind(@data,TypeInfo(TData),'FData1',EditN,'Text');

现在,Edit1的所有更改会自动填充到数据记录中的FData1字段,同样,对数据记录的FData1字段的所有更改都会自动显示在EditN的Text属性中。

线程安全是什么情况?

上面的例子显然有些简单。但是,由于两个绑定都引用了TControl子类,因此数据记录的轮询和更新需要在主应用程序/ GUI线程中完成,因此,除非您有另一个访问data.FData1的线程,否则这将安全地工作。

如果其他线程中修改记录的FData1字段,那你必须进行常规的线程数据锁定。可以用TkbmMWLock这个工具来帮助解决这个问题。

kbmMW SimpleBinding当然还支持任何组合中的对象实例作为数据源或者接收者。

Record可以绑定了,接下来,再看看

绑定对象列表

下面示例说明了如何绑定对象列表。首先让我们声明一个包含一些数据的列表。

type
TLine = class
private
FName:string;
FAddress:string;
public
constructor Create(const AName:string; const AAddress:string);
property Name:string read FName write FName;
property Address:string read FAddress write FAddress;
end; TLines = TObjectList<TLine>; var
lines:TLines;
...
lines:=TLines.Create;
lines.Add(TLine.Create('Hans','Hansvej 1'));
lines.Add(TLine.Create('Jens','Jensvej 1'));
lines.Add(TLine.Create('Frederik','Frederikvej 1'));
lines.Add(TLine.Create('Jonas','Jonasvej 1'));

现在让我们把lines对象列表与Edit1,Edit2可视控件进行绑定:

var
bnd:IkbmMWBinding;
begin
Binding.Clear;
bnd:=Binding.Bind(lines,'Name',Edit1,'Text');
Binding.Bind(lines,'Address',Edit2,'Text');
if bnd.Navigator<>nil then
bnd.Navigator.First;
end;

在这里,同时介绍了两个新内容:

  1. 使用Binding.Clear删除所有现有绑定
  2. 使用bnd.Navigator对列表进行导航。

请记住,如果有全局变量引用IkbmMWBinding,则必须在调用Binding.Clear之前将它们设置为nil 。如果不这样处理,特别是在将数据集作为数据源时(见后文),kbmMW将无法可靠地跟踪绑定之间的共享数据集。

调用Binding.Bind都会返回一个IkbmMWBinding接口,该接口可用于操作该特定绑定。IkbmMWBinding提供一个有用的属性是IkbmMWBindingNavigator类型的Navigator,通过Navigator可以轻松访问可导航的数据源...例如,象lines这样的列表对象。如果绑定的数据源不是列表,则Navigator为nil。

现在,你可以用bnd.Navigator.First/Last/Next/Previous进行导航,同时获取返回的书签。

对于特定来源的所有绑定,Navigator是常见且单一的。不同的可导航数据源具有自己的Navigator实例。

绑定数据集(TDataSet)

SmartBinding实现了可视控件与TDataSet子类的绑定,只要是TDataSet的子类,都可以绑定。现在,让我们通过将biolife.csv加载到TkbmMemTable中来制作数据源。

var
mt:TkbmMemTable;
csv:TkbmCSVStreamFormat;
begin
csv:=TkbmCSVStreamFormat.Create(nil);
try
mt:=TkbmMemTable.Create(nil);
mt.LoadFromFileViaFormat('biolife.csv',csv);
finally
csv.Free;
end;

接下来,让我们对Edit控件进行绑定:

     Binding.Clear;
bnd:=Binding.Bind(mt,'Category',Edit1,'Text',[mwboTwoWay]);
Binding.Bind(mt,'Species Name',Edit2,'Text',[mwboTwoWay]);
if bnd.Navigator<>nil then
bnd.Navigator.First;

与绑定对象列表一样,完全相同的绑定方式。在本例中,使用了双向绑定方式,即mwboTwoWay方式,目的是使Edit1和Edit2与Delphi的数据敏感控件TDBEdit控件的行为相同,可以利用导航器(bnd.Navigator),轻松导航数据集。

现在,在Edit1中输入内容,会自动保存到Category字段中,当mt的当前记录发生变化时,Edit1会显示当前记录的内容。另外,当用代码修改数据集的内容时,同样也会显示到对应有Edit控件中。如执行下面代码:

mt.Edit;
mt.FieldByName('Category').AsString:='测试!!!';
mt.Post;

Edit1的内容显示为测试!!!

绑定ListBox或ComboBox

有时候想要使用数据源列表/数据集(或其选定部分)来填充TListTCombobox(或其子类)。

对于此示例,我们还希望同步控件,即在其中一个控件中进行的选择会自动反映在另一个控件中。

     Binding.Clear;
Binding.Bind(mt,'Species Name',ComboBox1,'Items');
Binding.Bind(mt,'@',ComboBox1,'ItemIndex',[mwboTwoWay]);
bnd:=Binding.Bind(mt,'Common_Name',ListBox2,'Items');
Binding.Bind(mt,'@',ListBox2,'ItemIndex',[mwboTwoWay]);
if bnd.Navigator<>nil then
bnd.Navigator.First;

首先,我们将数据集mt中的Species Name字段绑定到TCombobox的Items属性,然后将另一个字段Common_Name绑定到TListBox的Items,之后,再使用@作为数据源属性,表示kbmMW SmartBinding引用数据源列表或者数据集的位置。这里,我们将数据源的位置绑定到TListBoxTComboboxItemIndex(位置)。此外,我们告诉SmartBinding用两种方式(mwboTwoWay),当更改数据源导航器中的位置不仅会更新TListBoxTCombobox中的位置,同时在控件中选择某些内容也会自动更新源列表/数据集位置,在这种情况下,确保两个控件彼此自动同步确保其来源一致。

绑定到Grid

看下面的代码,我们将数据集mt与Grid的指定列绑定,用@将数据集当前记录位置与Grid的当前行位置绑定,另外还用@将数据集位置与Grid的第一列绑定,同时,还将TEdit绑定到Grid的RowCount属性,所以能在运行期显示变化的Grid行数,即数据集的的记录数。

     Binding.Clear;
bnd:=Binding.Bind(mt,'Category',StringGrid1,'#1');
Binding.Bind(mt,'Species Name',StringGrid1,'#2');
Binding.Bind(mt,'@',StringGrid1,'@',[mwboTwoWay]);//将数据源与控件的位置进行双向绑定 // 在Grid的第一列显示位置数
Binding.Bind(mt,'@',StringGrid1,'#0'); // Bind to rowcount for easy on the fly change at runtime
Binding.Bind(leRowCount,'Text',StringGrid1,'RowCount'); if bnd.Navigator<>nil then
bnd.Navigator.First;

它仍然与我们习惯的绑定方式相同,但现在使用了#n语法,将数据集的字段绑定到Grid中的指定列(以0开头)。

使用导航器,Grid现在就像TDBGrid一样。因为我们将数据集的@与Grid的的@绑定到一起了,所以当滚动源数据集,Grid自动更新当前行位置,更改Grid当前选定行也将自动更新数据集的当前记录位置,数据集中当前记录的变化将自动反映在网格中,并且我们双向绑定方式,输入到网格中当前行的数据将反映回数据源。

2019-05-22 后记:笔者基于5.09版本做测试,用上面绑定的方法,在Grid中修改的结果,不会自动更新回数据集,如果用下面一行代码绑定:

bnd:=Binding.Bind(dataset,'Category',StringGrid1,'#1',[mwboTwoWay]);

则Grid中第一行显示不正常,去掉[mwboTwoWay],则正常显示。如下图:

第一行第一个字段没有显示。

绑定匿名函数

不仅对象、数据或数据集可以充当绑定的数据源或目标,匿名函数也可以。

     // Show calling function when Edit1.Text is changed.
Binding.Bind(Edit1,'Text',function(const AProxy:TkbmMWBindingCustomProxy; var AValue:TValue):boolean
begin
Log.Debug('Got change from binding to Edit1: '+AValue.ToString);
Result:=true;
end);

上面的示例基本上可以理解为将匿名函数作为Edit1.OnChange事件处理程序,Edit1.Text的变化将被检测到,自动执行匿名函数。在这个例子中,它使用kbmMW日志框架TkbmMWLog记录变化情况。

下面示例是如何使用匿名函数作为数据源:

     Binding.Bind(function(const AProxy:TkbmMWBindingCustomProxy; var AValue:TValue):boolean
begin
AValue:=Random();
Result:=true;
end,Edit1,'Text');

现在重复调用匿名函数。每次函数返回一个新值时,Edit1.Text都会更新。轮询函数的频率取决于我们用于定义绑定的Binding实例的属性UpdateFrequency的设置。默认频率是每秒10次,但您可以随时更改频率以符合您的喜好。

     Binding.UpdateFrequency:=;

扩充绑定

如果要定义从一个源获取数值的绑定,并将其输出到标签但格式不同,该怎么办?

您将使用从Binding.Bind函数返回的结果接口上可用的ToDestinationExpression方法。

     // Show calling function to populate Edit1.Text and format its look.
Binding.Bind(function(const AProxy:TkbmMWBindingCustomProxy; var AValue:TValue):boolean
begin
AValue:=Random();
Result:=true;
end,Edit1,'Text')
.ToDestinationExpression('"Hello "+data');

上面的代码,我们简单地用前面的函数绑定示例,并要求kbmMW SmartBinding根据ToDestinationExpression函数中给出的字符串表达式在目标路径上增加数据。此示例导致Edit1.Text包含值'Hello'和随机数。

因为字符串表达式基于kbmMW在其他地方利用的相同表达式处理功能,所以表达式非常丰富。这些功能源自具有kbmMemTables功能的SQL解析器和评估程序。在这种情况下,我们只支持像表达式部分这样的数学,而不是SQL本身。但是你可以使用你期望能够使用的所有常规操作,包括许多不错的转换,正则表达式,数学,条件评估和更多功能。

由于绑定可以是双向的,因此还需要能够在返回数据源时格式化或者可能格式化的值。为此,SmartBinding也提供了ToSourceExpression函数。

     Binding.Bind(Edit1,'Text',Edit2,'Text',[mwboTwoWay])
.ToDestinationExpression('"Hello "+data')
.ToSourceExpression('Mid(data,7)');

这个例子抓住Edit1.Text中的内容并将其放入Edit2.Text中,文本“Hello”为前缀。但是,它还可以识别Edit2.Text中所做的更改,并在首先删除它的前6个字符后将该文本移动到Edit1.Text。这种类型的双向绑定通常会使事件驱动的绑定变得疯狂,因为TEdit控件中的更改可能会发生无限的事件触发。但是,kbmMW SmartBinding不受这些事件的影响,并确保以最小的代价进行更新。

启用,禁用,解除绑定和重新绑定

有时您可能希望阻止绑定来完成其工作。如果预防只是暂时的,那么一种方法是禁用它。

var
bnd:IkbmMWBinding;
begin
bnd:=Binding.Bind(....);
...
bnd.Disable:=true;
...
bnd.Disable:=false;
end;

如果您想要永久禁用它,您也可以删除它。为此目的,存在Unbind方法。

Binding.UnbindSource(Edit1);

以上将取消绑定Edit1作为任何绑定的数据源。

Binding.UnbindDestination(Edit2);

以上将取消绑定Edit2作为任何绑定的目标。

您还可以使用调用Bind方法时返回的IkbmMWBinding取消绑定

var
MyBinding:IkbmMWBinding;
begin
MyBinding:=Binding.Bind(....);
...
Binding.Unbind(MyBinding);

如果您未绑定到匿名函数,则还可以使用与绑定完全相同的参数取消绑定

Binding.Bind(Edit1,'Text',Edit2,'Text');
...
Binding.Unbind(Edit1,'Text',Edit2,'Text');

最后你可能想要重新绑定。Rebind基本上可以修改从一个源或目标实例到另一个源或目标实例的绑定。绑定到瞬态记录或对象时特别有趣

Binding.Rebind(@data,@data2);

以上更改了引用记录或内存缓冲区“ 数据 ”的任何绑定,并更新这些绑定以引用记录或内存缓冲区“ data2 ”。

同样,您可以重新绑定控件

Binding.Rebind(Edit1,NewEdit1);

引用Edit1的所有绑定现在将引用NewEdit1

序幕

您可能已经注意到,运行时绑定的语法是一致且简单的,并且在重构用户界面或控件时可以轻松地重构绑定。

我之前提到过,除了现有的线程安全Binding单例之外,您还可以选择创建自己的绑定管理器实例。这样做的原因可能包括您希望不同的绑定在某种原因的不同时间间隔更新,或者您希望非常容易地访问丢弃或重新创建所有绑定,例如一个简单的框架中的框架,而不会影响定义的所有其他绑定在其他框架中,无需明确解除其中的每一个。

var
myBindingMgr:TkbmMWBindings;
begin
myBindingMgr:=TkbmMWBindings.Create();
...
myBindingMgr.Free;

上面的示例创建了另一个绑定管理器,它只会每秒轮询一次。当你不再需要它们时,请记得释放自己创建的绑定管理器。

我脑子里还有很多关于使绑定更容易并添加更多功能的想法,但这将是下一个完整版的kbmMW企业版中包含的beta代码。

如果您喜欢我们的产品和帖子,请与您认识的所有人分享这些帖子!

kbmMW用于简化软件开发的编码,让人专注于业务功能而不是基础代码。为什么?因为我讨厌在开发最终用户代码时做基础工作。所以实际上并没有为你开发所有这些东西,而是为了我自己使用,这很自私与自我,但希望你也会喜欢它。

哦..那个特色图片的含义是什么?
嗯..它可以解释很多方式......这里有一些

  • Smartbinding为那些从活动的悬崖上掉下来的人们进行救援
  • 绑定时,您需要确保绑定(系绳)是安全的,不会导致危险的问题
  • 做出自己的解释

https://components4developers.blog/2019/04/25/smartbinding-with-kbmmw-1/

2019-05-22 译者注:当前5.09版本已经发布,但SmartBinding不支持FMX ListView控件,这让我感到非常遗憾,因为我的app使用了大量的ListView。急盼作者能考虑在下一版本中实现。

后记:在5.10.20版本中,作者完美实现了!

SmartBinding与kbmMW#1的更多相关文章

  1. SmartBinding with kbmMW #4

    前言 在前面写过的文章中,详细介绍过如何将各种的控件与数据源进行绑定(Bind).在这篇文章中,将重点讨论如何绑定TImage和TListView.(同时支持VCL与Firemonkey). 将图形数 ...

  2. SmartBinding与kbmMW#3

    前言 在SmartBinding #2中,我介绍了新的自动绑定功能,支持在Form设计器中直接定义绑定.不仅如此,kbmMW SmartBind还有更多很酷的功能,即将发布的kbmMW中的SmartB ...

  3. SmartBinding与kbmMW#2

    前言 在之前的文章中,我介绍了SmartBinding作为Delphi的一个新的易于使用和智能的绑定框架.介绍了包括绑定对象,列表,常规数据和可视控件,以及如何使用导航器,所有这些都用代码做了演示. ...

  4. kbmMW 5.09测试报告(1)-Scheduler

    这个版本除了增加新的SmartBinding功能,同时提供了大量的功能更新以及bug修正.其中,SmartBinding的介绍,xalion已经第一时间写了初识kbmmw 中的smartbind功能, ...

  5. kbmMW 5.10.10 SmartBinding问题修正

    千呼万唤始出来,最新的kbmMW 5.10.01终于发布了,详情可以看xalion发的更新日志. 我期待的Smartbinding for Listview终于来了,在这一版本中,对SmartBind ...

  6. SmartBinding实现DataSet与ListView的绑定及同步显示

    kbmMW 5.10.10发布了,这个版本解决了我提出的问题,当对DataSet增删记录时,ListView能够同步显示.下面看看具体的实现代码. 为了解决上面的问题,作者为IkbmMWBinding ...

  7. SmartEvent with kbmMW #1

    前言 前面的文章,我写了有关SmartBinding框架方面的内容.SmartBinding的目的是将数据容器绑定到一起,通常情况下,数据容器可以是显示数据或与数据交互的控件(Edit,ListVie ...

  8. kbmMW 5.10.01试用报告

    1.FileClient.SameFile 调用这个方法,当本地文件不存在时,会一直等待.跟踪代码,发现: function TkbmMWCustomFileClient.SameFileEx(Loc ...

  9. SmartBinding工作原理分析

    关于kbmMW SmartBinding,我翻译了作者写的几篇文章,其强大的绑定机制,将可视控制与各种数据源灵活绑定在一起,实现了类似DBEdit数据敏感控件的效果,可以及大的减少我们的代码,实现界面 ...

随机推荐

  1. blob canvas img dataUrl的互相转换和用处

    blob:代表了一段二进制数据 初始化:var blob = new Blob(array,option)//其中array里面可以包含任意类型对象,option指数据类型如array是['<h ...

  2. JVM调优之JMeter使用(三)

    JMeter是Apache 下基于Java 的一款性能测试和压力测试工具.它基于Java 开发,可对HTTP 服务器和FTP服务器,甚至是数据库进行压力测试. 下载地址:http://jmeter.a ...

  3. Confluence 6 升级以后

    7. 拷贝你的数据库驱动 如果你现在使用的是 Oracle 或者 MySQL 数据库的话,你讲要重新拷贝 jdbc 驱动的 jar 文件到你已经存在的 Confluence 安装目录中 conflue ...

  4. MemSQL Start[c]UP 2.0 - Round 1E. Three strings

    题意:给3个字符串,问从1到min(l1,l2,l3)的长度的子串,找到从该位置长度为l,三个子串相同的三元组的个数 题解:把3个子串用分隔符串起来.然后分开统计每个节点在三个串中出现次数.最后乘起来 ...

  5. 【Mybatis】【3】mybatis Example Criteria like 模糊查询

    正文: 在Java中使用Mybatis自动生成的方法,like需要自己写通配符 public List<TableA> query(String name) { Example examp ...

  6. 使用js如何设置、获取盒模型的宽和高

    第一种: dom.style.width/height 这种方法只能获取使用内联样式的元素的宽和高. 第二种: dom.currentStyle.width/height 这种方法获取的是浏览器渲染以 ...

  7. 2n字符

    有2n字符挨个排成一排,前n个是'1',后n个是'0'.如 11110000(此时2n=8),现在交换字符的位置,使之按照 10101010 的模式排列.而且要使字符移动的次数最少,编程计算最少的移动 ...

  8. git相关操作记录

    拉取远端并强制覆盖本地文件 有时候会出现想放弃本地修改的情况,那么只需要下面几行命令 git fetch --all git reset --hard origin/master git pull / ...

  9. 小程序数据绑定点赞效果切换(交流QQ群:604788754)

    如果对本例有更好的意见和建议,希望给予留言或是加群跟群主联系,交流学习. WXML: <block wx:for="{{nums}}" wx:for-index='idx' ...

  10. linux php5.6 安装Redis扩展

    wget http://pecl.php.net/get/redis-4.2.0.tgz tar -zxvf redis-.tgz cd redis- /usr/local/php5./bin/php ...