You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Delphi LiveBindings将枚举自动转为字符串显示在网格中

解决RAD Studio LiveBindings枚举转字符串显示问题

问题背景

在使用RAD Studio的LiveBindings实现数据绑定时,为TPerson类定义了TGender枚举类型,通过TListBindSourceAdapter将TObjectList<TPerson>数据绑定到网格控件。已注册TConverterDescription实现枚举到字符串的转换,但网格中仍显示枚举的整数值,需要在不添加额外类字段的前提下实现枚举自动转为字符串显示。

解决方案

问题核心在于自动生成的网格绑定未启用自定义转换器,需通过以下步骤配置:

1. 优化转换器注册(可选)

可以保留原硬编码转换逻辑,也可以改用RTTI实现通用枚举名称获取,避免硬编码枚举值:

procedure RegisterConverters;
var
  RttiContext: TRttiContext;
  RttiType: TRttiEnumerationType;
begin
  TValueRefConverterFactory.RegisterConversion(TypeInfo(TGender), TypeInfo(string),
    TConverterDescription.Create(
      procedure(const InValue: TValue; var OutValue: TValue)
      var
        Gender: TGender;
      begin
        Gender := InValue.AsType<TGender>;
        // 特殊值自定义显示,其余用RTTI获取枚举名称
        if Gender = NonBinary then
          OutValue := TValue.From<string>('Non Binary')
        else
        begin
          RttiContext := TRttiContext.Create;
          try
            RttiType := RttiContext.GetType(TypeInfo(TGender)) as TRttiEnumerationType;
            OutValue := TValue.From<string>(RttiType.GetName(Gender));
          finally
            RttiContext.Free;
          end;
        end;
      end,
      'TGenderToString', 'TGenderToString', EmptyStr, True, EmptyStr, nil)
  );
end;

initialization
  RegisterConverters;

2. 为网格绑定的Gender列指定转换器

自动生成的TLinkGridToDataSource不会自动应用转换器,需手动指定:

方法一:设计时配置

  1. 打开窗体设计器,选中BindingsList1中的LinkGridToDataSourceAdapterBindSource12
  2. 在Object Inspector中找到Columns属性,展开后选中Gender项
  3. 设置OutputConverterName为TGenderToString(即注册转换器时指定的名称)

方法二:代码动态配置

在窗体的FormCreate事件中添加代码:

procedure TMainForm.FormCreate(Sender: TObject);
var
  Col: TLinkGridColumn;
begin
  Col := LinkGridToDataSourceAdapterBindSource12.Columns.FindMember('Gender');
  if Assigned(Col) then
    Col.OutputConverterName := 'TGenderToString';
end;

3. 替代方案:使用网格OnGetValue事件直接转换

如果不想依赖LiveBindings转换器,也可以通过网格的OnGetValue事件直接处理显示逻辑:

procedure TMainForm.Grid1GetValue(Sender: TObject; const ACol, ARow: Integer; var Value: TValue);
var
  Person: TPerson;
begin
  // 假设Gender是第4列(索引从0开始为3)
  if ACol = 3 then
  begin
    Person := fMyPeople[ARow];
    case Person.Gender of
      Female: Value := 'Female';
      NonBinary: Value := 'Non Binary';
    else
      Value := 'Male';
    end;
  end;
end;

注意:这种方法需要确保列索引对应正确,且fMyPeople是窗体类可访问的字段。

修改后的完整uMain.pas代码

unit uMain;

interface

uses
  Spring.Data.ObjectDataSet,
  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.Components,
  Data.Bind.ObjectScope, CollectionObjects, System.Rtti, Fmx.Bind.Grid,
  System.Bindings.Outputs, Fmx.Bind.Editors, Data.Bind.Grid, FMX.Layouts,
  FMX.Grid, FMX.Controls.Presentation, FMX.StdCtrls,
  System.Generics.Collections, REST.JSON,
  Data.Bind.GenData, FMX.ScrollBox, FMX.Memo, FMX.TabControl,
  Data.Bind.Controls, Fmx.Bind.Navigator, FMX.Grid.Style, System.JSON, FMX.Memo.Types;

type

  TGender = (Male, Female, NonBinary);

  TPerson = class
  private
    FAge: Integer;
    FLastName: string;
    FFirstName: string;
    FGender: TGender;
  public
    constructor Create(FirstName, LastName: String; Age: Integer; Gender: TGender);
    property FirstName: string read FFirstName write FFirstName;
    property LastName: string read FLastName write FLastName;
    property Age: Integer read FAge write FAge;
    property Gender: TGender read FGender write FGender;
  end;

  TMainForm = class(TForm)
    AdapterBindSource1: TAdapterBindSource;
    BindingsList1: TBindingsList;
    TabControl1: TTabControl;
    GridTab: TTabItem;
    Grid1: TGrid;
    LinkGridToDataSourceAdapterBindSource12: TLinkGridToDataSource;
    DataGeneratorAdapter1: TDataGeneratorAdapter;
    NavigatorAdapterBindSource1: TBindNavigator;
    procedure AdapterBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
    procedure FormCreate(Sender: TObject);
    // 可选:添加OnGetValue事件
    // procedure Grid1GetValue(Sender: TObject; const ACol, ARow: Integer; var Value: TValue);
  private
    fMyPeople: TObjectList<TPerson>;
    fMyPeopleDB: TObjectDataSet;
  public
  end;

var
  MainForm: TMainForm;

implementation

{$R *.fmx}
{$R *.LgXhdpiPh.fmx ANDROID}
{$R *.iPhone4in.fmx IOS}

constructor TPerson.Create(FirstName, LastName: String; Age: Integer; Gender: TGender);
begin
  FFirstName := FirstName;
  FLastName := LastName;
  FAge := Age;
  FGender := Gender;
end;

procedure TMainForm.AdapterBindSource1CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  fMyPeople := TObjectList<TPerson>.Create;

  fMyPeople.Add(TPerson.Create('Gomez', 'Addams', 40, Male));
  fMyPeople.Add(TPerson.Create('Morticia', 'Addams', 38, Female));
  fMyPeople.Add(TPerson.Create('Pugsley', 'Addams', 8, NonBinary));
  fMyPeople.Add(TPerson.Create('Wednesday', 'Addams', 12, NonBinary));

  fMyPeople.Add(TPerson.Create('Uncle', 'Fester', 55, Male));
  fMyPeople.Add(TPerson.Create('Grandmama', 'Frump', 72, Female));
  fMyPeople.Add(TPerson.Create('', 'Lurch', 50, Male));
  fMyPeople.Add(TPerson.Create('Thing T.', 'Thing', 99, NonBinary));
  fMyPeople.Add(TPerson.Create('Cousin', 'Itt', 21, NonBinary));

  ABindSourceAdapter := TListBindSourceAdapter<TPerson>.Create(Self, fMyPeople, True);
end;

procedure TMainForm.FormCreate(Sender: TObject);
var
  Col: TLinkGridColumn;
begin
  Col := LinkGridToDataSourceAdapterBindSource12.Columns.FindMember('Gender');
  if Assigned(Col) then
    Col.OutputConverterName := 'TGenderToString';
end;

// 可选:OnGetValue事件实现
// procedure TMainForm.Grid1GetValue(Sender: TObject; const ACol, ARow: Integer; var Value: TValue);
// var
//   Person: TPerson;
// begin
//   if ACol = 3 then
//   begin
//     Person := fMyPeople[ARow];
//     case Person.Gender of
//       Female: Value := 'Female';
//       NonBinary: Value := 'Non Binary';
//     else
//       Value := 'Male';
//     end;
//   end;
// end;

procedure RegisterConverters;
var
  RttiContext: TRttiContext;
  RttiType: TRttiEnumerationType;
begin
  TValueRefConverterFactory.RegisterConversion(TypeInfo(TGender), TypeInfo(string),
    TConverterDescription.Create(
      procedure(const InValue: TValue; var OutValue: TValue)
      var
        Gender: TGender;
      begin
        Gender := InValue.AsType<TGender>;
        if Gender = NonBinary then
          OutValue := TValue.From<string>('Non Binary')
        else
        begin
          RttiContext := TRttiContext.Create;
          try
            RttiType := RttiContext.GetType(TypeInfo(TGender)) as TRttiEnumerationType;
            OutValue := TValue.From<string>(RttiType.GetName(Gender));
          finally
            RttiContext.Free;
          end;
        end;
      end,
      'TGenderToString', 'TGenderToString', EmptyStr, True, EmptyStr, nil)
  );
end;

initialization
  RegisterConverters;

end.

内容的提问来源于stack exchange,提问作者Rick Wheeler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:29:59