一步一步学习使用LiveBindings(7) 实现对JSON数据的绑定
一步一步学习使用LiveBindings(7) 实现对JSON数据的绑定
本课将介绍如何从JSON中获取绑定数据源,并且将更新也写回JSON。可以设想一下有一台远端服务器提供JSON数据,Delphi客户端可以接收这些JSON数据,然后转换成数据绑定对象,在应用程序中处理完数据后,将更新的数据序列化为JSON传回远端服务器,很多移动应用使用了这种模式处理服务器端的数据。好了废话少说,开始打开Delphi 12.3,建项目吧。
本系列课程具有前后关联性,如果你对LiveBindings的诸多细节没有一个大的概念,请看一步一步学习使用LiveBindings的前几课。
1. 单击主菜单中的 File > New > Multi-Device Application - Delphi > Blank Application ,创建一个新的多设备应用程序。
建议立即单击工具栏上的Save All按钮,将单元文件保存为uMainForm.pas,将项目保存为LiveBinding_BindToJSON.dproj。
你的项目结构应该像这样:

首先新建一个名为CollectionObjects.pas的Unit,右键单击Project Manager中的项目名称,选择“Add New > Unit”,保存为CollectionObjects.pas文件名,CollectionObjects.pas包含一个简单的TPerson类,你可以想象为一个业务实体,代码如下:
//
unit CollectionObjects;
interface
type
TPerson = class
private
FAge: Integer;
FLastName: string;
FFirstName: string;
public
constructor Create(const FirstName, LastName: String; Age: Integer);
property FirstName: string read FFirstName write FFirstName;
property LastName: string read FLastName write FLastName;
property Age: Integer read FAge write FAge;
end;
implementation
{ TPerson }
constructor TPerson.Create(const FirstName, LastName: String; Age: Integer);
begin
FFirstName := FirstName;
FLastName := LastName;
FAge := Age;
end;
end.
代码过于简洁,无须过多介绍。
2. 在主窗体上,放一个TTabControl控件,为该控件添加2个TabItem,一个指定Text为"Grid",一个指定Text为“JSON”,这个名为JSON的Tab页用来演示后台的JSON数据的变化,用户将可以编辑这个JSON,同时在Grid上看到更新。
在名为TabGrid的TabItem上,放置一个TGrid和一个TBindNavigator控件,在名为TabJSON的TabItem上,放置一个TMemo控件用来显示JSON内容。
最后放置一个TDataGeneratorAdapter和一个TAdapterBindSource,指定AdapterBindSource1的Adapter为DataGeneratorAdapter1,BindNavigator1的DataSource属性为AdapterBindSource1。
设计窗口如下图所示:

3. 接下来需要完成绑定工作,目前AdapterBindSource1虽然指向了DataGeneratorAdapter1,但是DataGeneratorAdapter1还没有设置字段和相应的数据生成器。现在右击DataGeneratorAdapter1,从弹出的菜单中选择“Fields Editor”菜单项,根据在CollectionObjects.pas单元中定义的TPerson类的属性来创建3个字段,并分别指定如下图所示的数据生成器。

4. 在TGrid上右击鼠标,从弹出的菜单中选择“Bind Visually”,在LiveBinding Designer中,将AdapterBindSource1的字段分别拖放到MainGrid上,可以看到生成的数据会立即显示在Grid上。

注意:拖动单独的列到Grid,可以单独调整Grid列的属性。
到目前为止,就构建了一个具有样例数据的应用程序。
5. 由于示例没有真正的访问远端服务器,为了演示数据绑定的效果,接下来实现AdapterBindSource1的OnCreateAdapter事件,在该事件中添加测试数据,以便在Grid上可以看到“真实”的数据。
首先在Interface区的uses下面添加类引用,并在private区添加一个泛型集合类。
unit uMainForm;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TabControl,
Data.Bind.Controls, System.Rtti, FMX.Grid.Style, FMX.Memo.Types,
Data.Bind.Components, Data.Bind.ObjectScope, FMX.Memo,
FMX.Controls.Presentation, FMX.ScrollBox, FMX.Grid, FMX.Layouts,
Fmx.Bind.Navigator, Data.Bind.GenData, Data.Bind.EngExt, Fmx.Bind.DBEngExt,
System.Bindings.Outputs, Data.Bind.Grid, Fmx.Bind.Grid, Fmx.Bind.Editors,
//添加如下的单元引用
CollectionObjects,System.Generics.Collections,REST.Json,System.JSON;
type
TfrmMain = class(TForm)
Tab: TTabControl;
tabGrid: TTabItem;
tabJSON: TTabItem;
NavigatorAdapterBindSource1: TBindNavigator;
mmJSON: TMemo;
DataGeneratorAdapter1: TDataGeneratorAdapter;
AdapterBindSource1: TAdapterBindSource;
grdMain: TGrid;
BindingsList1: TBindingsList;
LinkGridToDataSourceAdapterBindSource1: TLinkGridToDataSource;
private
{ Private declarations }
//添加保存人员信息的泛型列表类
FMyPeople: TObjectList<TPerson>;
public
{ Public declarations }
end;
在单元引用区,可以看到添加了System.JSON和REST.JSON引用,它们将用来处理JSON的解析与生成。
接下来在AdapterBindSource1的OnCreateAdapter事件中添加一些模拟的人员数据,如下代码所示:
procedure TfrmMain.AdapterBindSource1CreateAdapter(Sender: TObject;
var ABindSourceAdapter: TBindSourceAdapter);
begin
//用来保存人员数据的集合。
FMyPeople := TObjectList<TPerson>.Create(True);
//添加单个的人员信息
FMyPeople.Add(TPerson.Create('Gomez', 'Addams', 40));
FMyPeople.Add(TPerson.Create('Morticia', 'Addams', 38));
FMyPeople.Add(TPerson.Create('Pugsley', 'Addams', 8));
FMyPeople.Add(TPerson.Create('Wednesday', 'Addams', 12));
FMyPeople.Add(TPerson.Create('Uncle', 'Fester', 55));
FMyPeople.Add(TPerson.Create('Grandmama', 'Frump', 72));
FMyPeople.Add(TPerson.Create('', 'Lurch', 50));
FMyPeople.Add(TPerson.Create('Thing T.', 'Thing', 99));
FMyPeople.Add(TPerson.Create('Cousin', 'Itt', 21));
// 使用TListBindSourceAdapter绑定到集合数据。
ABindSourceAdapter := TListBindSourceAdapter<TPerson>.Create(Self, FMyPeople, True);
end;
现在运行示例,可以看到这些数据已经显示在了Grid上,可以进行上下移动编辑了。

6. 搞定了数据绑定的问题,现在真正要解决的问题是将TObjectList类型的泛型集合转换成JOSN字符串发送给服务器,或者是在接收到JSON字符串后,转换为TObjectList类型的泛型集合以更新绑定UI,在这里需要引入2个过程。
在private区域定义2个过程,用来分别将对象转换为JSON以及将JSON转换为对象。
private
{ Private declarations }
//添加保存人员信息的泛型列表类
FMyPeople: TObjectList<TPerson>;
//将对象转换为JSON数据
procedure ObjectsToJson;
//将JSON转换为对象
procedure JsonToObjects;
Implementation
procedure TfrmMain.JsonToObjects;
begin
//TODO 将TMemo中的JSON字符串转换为对象
end;
procedure TfrmMain.ObjectsToJson;
begin
//TODO 将TGrid绑定的对象转换为JSON字符串显示在TMemo中。
end;
由于ObjectsToJson和JsonToObjects涉及到一些JSON相关的操作,咱们需要先想想如何实现,但是UI的布局应该是当Tab切换时,如果切换到Grid这个Tab页,则调用JsonToObjects更新Grid上的数据;如果切换到JSON这个Tab页,则调用ObjectsToJson将Grid上的更新序列化为JSON字符串,所以应该是这样的一个效果:

可以看到,JSON与Grid是同步的,两边都可以更改。
7. 在主窗体中选中TTabControl控件,在属性编辑器中切换到Event标签页,找到OnChange事件,添加如下的代码:
procedure TfrmMain.TabChange(Sender: TObject);
begin
//如果当前页面是JSON页
if Tab.ActiveTab = tabJSON then
begin
//如果AdapterBindSource处于编辑模式,则提交。
if AdapterBindSource1.Editing then
AdapterBindSource1.Post;
ObjectsToJson; //将对象转换为JSON。
end
else if Tab.ActiveTab = tabGrid then
JsonToObjects; //反之将JSON转换为对象。
end;
8. 在开始这2个核心的过程之前,良好的可重用的代码设计就显得很重要。System.JSON单元封装了JSON对象操作的逻辑,REST.JSON则提供了单一JSON字符串转换为对象或者对象到JSON字符串的转换功能。在这里封装了一个名为TUtils的类,它包含2个类方法:
type
TUtils = class
public
//将一个泛型列表对象转换为JSON数组
class function ObjectListToJSON<T: class>(const AObjects: TObjectList<T>): TJSONArray;
//将一个JSON数组转换为泛型列表对象
class function JsonToObjectList<T: class, constructor>(const AText: string): TObjectList<T>;
end;
{ TUtils }
class function TUtils.JsonToObjectList<T>(const AText: string): TObjectList<T>;
var
LObject: T;
LArray: TJSONArray;
LValue: TJSONValue;
LList: TObjectList<T>;
begin
LList := TObjectList<T>.Create;
LArray := nil;
try
LArray := TJSONObject.ParseJSONValue(AText) as TJSONArray;
if LArray = nil then
raise Exception.Create('Invalid JSON');
for LValue in LArray do
if LValue is TJSONObject then
begin
//使用REST.Json提供的TJson类的类方法完成转换
LObject := TJson.JsonToObject<T>(TJSONObject(LValue));
LList.Add(LObject);
end;
Result := LList;
LList := nil;
finally
LArray.Free;
LList.Free;
end;
end;
class function TUtils.ObjectListToJSON<T>(
const AObjects: TObjectList<T>): TJSONArray;
var
LObject: T;
LArray: TJSONArray;
LValue: TPerson;
LElement: TJSONObject;
begin
LArray := TJSONArray.Create;
try
for LObject in AObjects do
begin
//使用REST.Json提供的TJson类的类方法完成转换
LElement := TJson.ObjectToJsonObject(LObject);
LArray.AddElement(LElement);
end;
Result := LArray;
LArray := nil;
finally
LArray.Free;
end;
end;
代码中的TJSONArray,TJSONObject类是由System.Json的供来操纵JSON的,核心部分的TJson类是由REST.Json所提供,顾名思议,这个单元是处理Restful操作的。
9. 现在一切准备就绪,继续完成ObjectsToJson和JsonToObjects这两个过程,代码如下所示:
procedure TfrmMain.JsonToObjects;
begin
//使用JsonToObjectList将JSON转换为对象
fMyPeople := TUtils.JsonToObjectList<TPerson>(mmJSON.Text);
//将列表数据重新赋给AdapterBindSource1。
TListBindSourceAdapter<TPerson>(AdapterBindSource1.InternalAdapter).SetList(fMyPeople);
//刷新用户界面
AdapterBindSource1.Active := True;
end;
procedure TfrmMain.ObjectsToJson;
var
LArray: TJSONArray;
begin
//将对象转换为TJSONArray数组
LArray := TUtils.ObjectListToJSON<TPerson>(fMyPeople);
try
//将JSON数组稍稍美经后显示在TMemo控件
mmJSON.Text := PrettyJSON(LArray.ToString);
finally
LArray.Free;
end;
end;
function PrettyJSON(AJson: String): String;
begin
Result := StringReplace(AJson, '},', '},' + sLineBreak, [rfReplaceAll]);
Result := StringReplace(Result, '[{', '[' + sLineBreak + '{', [rfReplaceAll]);
end;
10. 万事皆备,只欠一Run了,按下F9,或者是主菜单的“Run > Run”,可以看到JOSN和Grid的数据果然已经同步了。
真实的项目中,JSON生成后,应该是要发送给Server端,或者存储到本地文件,这可以根据需要而定。
本课就讲到这里了,虽然到目前为止笔者还没有深挖TBindingList的内幕,不过可以看到使用LiveBindings Designer已经可以解决不少问题了。当然在实际的项目中还是有很多细节要处理的,比如显式格式的转换,复杂的绑定场景等等。
在本系列的后面的课程中会继续深挖。
一步一步学习使用LiveBindings(7) 实现对JSON数据的绑定的更多相关文章
- 【Spring学习笔记-MVC-4】SpringMVC返回Json数据-方式2
<Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...
- 【Spring学习笔记-MVC-3】SpringMVC返回Json数据-方式1
<Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...
- 只要三步!阿里云DLA帮你处理海量JSON数据
概述 您可能有大量应用程序产生的JSON数据,您可能需要对这些JSON数据进行整理,去除不想要的字段,或者只保留想要的字段,或者仅仅是进行数据查询. 那么,利用阿里云Data Lake Analyti ...
- Android 学习笔记之Volley(七)实现Json数据加载和解析...
学习内容: 1.使用Volley实现异步加载Json数据... Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...
- 我的angularjs源码学习之旅3——脏检测与数据双向绑定
前言 为了后面描述方便,我们将保存模块的对象modules叫做模块缓存.我们跟踪的例子如下 <div ng-app="myApp" ng-controller='myCtrl ...
- 【Struts2学习笔记-8】Struts2实现json数据的返回
需要的jar包 struts2-json-plugin-2.3.12.jar xwork-core-2.3.16.3.jar struts.xml 来自为知笔记(Wiz) 附件列表 IMG_20150 ...
- Knockout.Js官网学习(加载或保存JSON数据)
前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...
- (转)SpringMVC学习(十)——SpringMVC与前台的json数据交互
http://blog.csdn.net/yerenyuan_pku/article/details/72514022 json数据格式在接口调用中.html页面中比较常用,json格式比较简单,解析 ...
- 初识Scrapy——1—scrapy简单学习,伯乐在线实战、json数据保存
Scrapy——1 目录 什么是Scrapy框架? Scrapy的安装 Scrapy的运行流程 Scrapy的使用 实战:伯乐在线案例(json文件保存) 什么是Scrapy框架? Scrapy是用纯 ...
- (数据科学学习手札126)Python中JSON结构数据的高效增删改操作
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在上一期文章中我们一起学习了在Python ...
随机推荐
- C#之并发字典
internal class Program { const string Item = "Dictionary item"; const int Iterations = 100 ...
- C#8.0,9.0,10.0常见新语法学习
顶级语句 (1)一个项目最多只能有一个文件具有顶级语句,就是直接写代码,如果存在多个,则会报错, (2)如果顶级语句和Main共存,则只调用顶级语句 (3)如果没有顶级语句,则必须有Main 简化us ...
- BootStrap CDN收藏,矢量图标
<!-- 新 Bootstrap 核心 CSS 文件 --> <link href="https://cdn.staticfile.org/twitter-bootstra ...
- 1-1, 一个简单的mysql 安装教程,基于mysql 5.7解压版本.
下载mysql. 略,去官网 1. 配置my.cnf. 把mysql提供的配置模板 copy到/etc/my.cnf (先读取/etc/my.cnf,再去读/etc/mysql/my.cnf,第三个读 ...
- 使用Plop.js高效生成模板文件
前情 开发是个创造型的职业,也是枯燥的职业,因为开发绝大多数都是每天在业务的代码中无法自拨,说到开发工作,就永远都逃不开新建文件的步骤,特别现在组件化开发胜行,每天都是在新建新建组件的道路上一去不返, ...
- 未来已来?vSphere 9 预览版部署体验
最近看到不少技术爱好者开始分享 vSphere 9 的基础体验镜像,作为 VMware 的忠实粉丝,怎么能错过这波"尝鲜"机会呢? 趁着空闲时间,我也动手安装体验了一下.从初步使用 ...
- Tomcat基础学习
Tomcat简介 Tomcat是一个轻量级的web服务器,也称为web容器,servlet容器.(web服务器可以封装http协议,简化开发.还可以将web项目部署到服务器上,对外提供网上浏览.) T ...
- 三种熔断策略在数据服务API中的实践应用
熔断策略的概念最早可以追溯到电力系统中的保险丝.当电流过大时,保险丝会自动熔断,以防止电器设备因过载而损坏.这种简单而有效的保护机制为后来软件系统中的熔断策略提供了灵感.在软件系统中,熔断策略的工作原 ...
- 数栈大数据组件:Hive优化之配置参数的优化
Hive是大数据领域常用的组件之一,主要用于大数据离线数仓的运算,关于Hive的性能调优在日常工作和面试中是经常涉及的一个点,因此掌握一些Hive调优是必不可少的一项技能.影响Hive效率的主要因素有 ...
- jenkins部署到另一台服务器
安装插件 搜索安装插件:publish over ssh 配置插件 系统管>SSH Servers 前端部署到另一台服务器 其实前端就是将编译后的代码传送至目标服务器的nginx的html目录下 ...