Delphi 利用LiveBindings绑定JSON数据到列表控件

Delphi通过HTTP接口从远程服务器获取JSON数据,并显示在TStringGrid控件上。

一、LiveBindings技术简介

为了提供数据绑定方案,Delphi FMX 框架提供了 LiveBindings 的技术。

LiveBindings 基本上是一种基于表达式的机制,其中通常有一个源组件和一个目标组件,目的是将一个或多个涉及源成员的表达式绑定到目标的一个或多个属性。为了实现这一点,系统需要在某个地方存储涉及组件(在表单、框架或数据模块中)的绑定表达式集合(TBindingList 组件)。为了使数据对表达式引擎可用,需要使用中间组件(BindSources)在表达式引擎和实际数据存储之间充当中介。

其中BindSources组件包含TBindSourceDB、TBindSourceDBX、TPrototypeBindSource、TAdapterBindSource。

TBindSourceDB或TBindSourceDBX的DataSet属性可以连接TFDMemTable等数据库控件;

TAdapterBindSource的Adapter属性连接TDataGeneratorAdapter控件,继而绑定TList<T>数据集。

二、解决方案

以Delphi 12.1作为开发工具,用网格控件TStringGrid显示员工信息的JSON数据,JSON数据如下:

[{"name":"宋江",
"age":29,
"mobile":"13812345678",
"startDate":"2023-09-11",
"position":"developer"
},
{"name":"卢俊义",
"age":29,
"mobile":"13812345678",
"startDate":"2023-09-11",
"position":"developer"
},
{"name":"吴用",
"age":29,
"mobile":"13812345678",
"startDate":"2023-09-11",
"position":"developer"
},
{"name":"林冲",
"age":29,
"mobile":"13812345678",
"startDate":"2023-09-11",
"position":"developer"
}]

1、窗体上添加 TBindingsList、 TAdapterBindSource、TDataGeneratorAdapter、TBindNavigator、TStringGrid组件

2、双击BindingsList1,添加TBindGridLink类型的数据绑定表达式,源组件选择AdapterBindSource1,目标组件选择StringGrid1

3、将AdapterBindSource1的Adapter设置为 DataGeneratorAdapter1

4、将BindNavigator1的DataSource设置为AdapterBindSource1

5、新建TEmployee类

TEmployee = class(TObject)
  private
    FName: String;
    FAge: string;
    FMobile: string;
    FStartDate: string;
    FPosition: String;
  public
    constructor Create(const AName: String; const AAge: string; const AMobile: string;
                       const AStartDate: string; const APosition: String); overload;
    property Name: String read FName write FName;
    property Age: string read FAge write FAge;
    property Mobile: String read FMobile write FMobile;
    property StartDate: string read FStartDate write FStartDate;
    property Position: String read FPosition write FPosition;
  end;

{ TEmployee }

constructor TEmployee.Create(const AName: String; const AAge: string;
  const AMobile: string; const AStartDate: string; const APosition: String);
begin
  inherited Create;

  FName := AName;
  FAge := AAge;
  FMobile := AMobile;
  FStartDate := AStartDate;
  FPosition := APosition;
end;

6、解析JSON数据,转为TList<TEmployee>

procedure TForm1.LoadEmployListDataFromJson(AJsonStr: string);
var
  i: Integer;
  ja: TJsonArray;
  jo: TJSONObject;
  lEmployee: TEmployee;
begin
  ja := TJSONObject.ParseJSONValue(AJsonStr) as TJSONArray;
  try
    // 注意:这里 EmployeeList 不用释放,因为它会添加到TListBindSourceAdapter,并释放
    EmployeeList := TList<TEmployee>.Create;

    for i := 0 to ja.Count-1 do
    begin
      jo := ja.Items[i] as TJSONObject;
      lEmployee := TEmployee.Create(jo.GetValue('name').ToString, jo.GetValue('age').ToString,
        jo.GetValue('mobile').ToString, jo.GetValue('startDate').ToString, jo.GetValue('position').ToString);
      EmployeeList.Add(lEmployee);
    end;
  finally
    ja.Free;
  end;
end;

7、通过AdapterBindSource1的onCreateAdapter事件为TDataGeneratorAdapter添加TList<TEmployee>数据

procedure TForm1.AdapterBindSource1CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  LoadEmployListDataFromJson(employeeJson);

  // 将 EmployeeList 数据绑定到 DataGeneratorAdapter1
  // 其中 Create 方法的参数 AOwnsObject 默认为 true,控件释放时,会释放 EmployeeList 对象
  ABindSourceAdapter := TListBindSourceAdapter<TEmployee>.Create(Self, EmployeeList);
end;

三、代码实现

完整代码如下:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  Data.Bind.EngExt, Fmx.Bind.DBEngExt, Data.Bind.GenData, System.Rtti,
  FMX.Grid.Style, Data.Bind.Controls, System.Bindings.Outputs, Fmx.Bind.Editors,
  Data.Bind.Components, FMX.Layouts, Fmx.Bind.Navigator,
  FMX.Controls.Presentation, FMX.ScrollBox, FMX.Grid, Data.Bind.ObjectScope,
  System.Generics.Collections, System.JSON, Fmx.Bind.Grid, Data.Bind.Grid,
  FMX.Objects;

const
  employeeJson = '[{"name":"宋江","age":29,"mobile":"13812345678","startDate":"2023-09-11","position":"developer"},'
    + '{"name":"卢俊义","age":29,"mobile":"13812345678","startDate":"2023-09-11","position":"developer"},'
    + '{"name":"吴用","age":29,"mobile":"13812345678","startDate":"2023-09-11","position":"developer"}, '
    + '{"name":"林冲","age":29,"mobile":"13812345678","startDate":"2023-09-11","position":"developer"}]';

type
  TEmployee = class(TObject)
  private
    FName: String;
    FAge: string;
    FMobile: string;
    FStartDate: string;
    FPosition: String;
  public
    constructor Create(const AName: String; const AAge: string; const AMobile: string;
                       const AStartDate: string; const APosition: String); overload;
    property Name: String read FName write FName;
    property Age: string read FAge write FAge;
    property Mobile: String read FMobile write FMobile;
    property StartDate: string read FStartDate write FStartDate;
    property Position: String read FPosition write FPosition;
  end;

  TForm1 = class(TForm)
    BindingsList1: TBindingsList;
    AdapterBindSource1: TAdapterBindSource;
    DataGeneratorAdapter1: TDataGeneratorAdapter;
    StringGrid1: TStringGrid;
    BindNavigator1: TBindNavigator;
    LinkGridToDataSourceAdapterBindSource1: TLinkGridToDataSource;
    Text1: TText;
    procedure AdapterBindSource1CreateAdapter(Sender: TObject;
      var ABindSourceAdapter: TBindSourceAdapter);
  private
    { Private declarations }
    EmployeeList: TList<TEmployee>;
    procedure LoadEmployListDataFromJson(AJsonStr: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ TEmployee }

constructor TEmployee.Create(const AName: String; const AAge: string;
  const AMobile: string; const AStartDate: string; const APosition: String);
begin
  inherited Create;

  FName := AName;
  FAge := AAge;
  FMobile := AMobile;
  FStartDate := AStartDate;
  FPosition := APosition;
end;

{ TForm1 }

procedure TForm1.AdapterBindSource1CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  LoadEmployListDataFromJson(employeeJson);

  // 将 EmployeeList 数据绑定到 DataGeneratorAdapter1
  // 其中 Create 方法的参数 AOwnsObject 默认为 true,控件释放时,会释放 EmployeeList 对象
  ABindSourceAdapter := TListBindSourceAdapter<TEmployee>.Create(Self, EmployeeList);
end;

procedure TForm1.LoadEmployListDataFromJson(AJsonStr: string);
var
  i: Integer;
  ja: TJsonArray;
  jo: TJSONObject;
  lEmployee: TEmployee;
begin
  ja := TJSONObject.ParseJSONValue(AJsonStr) as TJSONArray;
  try
    // 注意:这里 EmployeeList 不用释放,因为它会添加到TListBindSourceAdapter,并释放
    EmployeeList := TList<TEmployee>.Create;

    for i := 0 to ja.Count-1 do
    begin
      jo := ja.Items[i] as TJSONObject;
      lEmployee := TEmployee.Create(jo.GetValue('name').ToString, jo.GetValue('age').ToString,
        jo.GetValue('mobile').ToString, jo.GetValue('startDate').ToString, jo.GetValue('position').ToString);
      EmployeeList.Add(lEmployee);
    end;
  finally
    ja.Free;
  end;
end;

end.

窗体文件: 

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 451
  ClientWidth = 582
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object StringGrid1: TStringGrid
    CanFocus = True
    ClipChildren = True
    Position.X = 64.000000000000000000
    Position.Y = 144.000000000000000000
    Size.Width = 425.000000000000000000
    Size.Height = 241.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 3
    RowCount = 200
    Viewport.Width = 421.000000000000000000
    Viewport.Height = 216.000000000000000000
  end
  object BindNavigator1: TBindNavigator
    Position.X = 64.000000000000000000
    Position.Y = 393.000000000000000000
    Size.Width = 425.000000000000000000
    Size.Height = 41.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 4
    DataSource = AdapterBindSource1
    xRadius = 4.000000000000000000
    yRadius = 4.000000000000000000
  end
  object Text1: TText
    Position.X = 64.000000000000000000
    Position.Y = 40.000000000000000000
    Size.Width = 425.000000000000000000
    Size.Height = 73.000000000000000000
    Size.PlatformDefault = False
    Text = #29992'LiveBindings'#23454#29616#32465#23450'JSON'#25968#25454#21040'Grid'
    TextSettings.Font.Size = 18.000000000000000000
    TextSettings.FontColor = claCoral
  end
  object BindingsList1: TBindingsList
    Methods = <>
    OutputConverters = <>
    Left = 112
    Top = 232
    object LinkGridToDataSourceAdapterBindSource1: TLinkGridToDataSource
      Category = 'Quick Bindings'
      DataSource = AdapterBindSource1
      GridControl = StringGrid1
      Columns = <>
    end
  end
  object AdapterBindSource1: TAdapterBindSource
    AutoActivate = True
    OnCreateAdapter = AdapterBindSource1CreateAdapter
    Adapter = DataGeneratorAdapter1
    ScopeMappings = <>
    Left = 240
    Top = 232
  end
  object DataGeneratorAdapter1: TDataGeneratorAdapter
    FieldDefs = <>
    Active = True
    AutoPost = False
    Options = [loptAllowInsert, loptAllowDelete, loptAllowModify]
    Left = 392
    Top = 232
  end
end

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值