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

Delphi LiveBindings绑定TGrid时Currency/BCD字段显示(BCD)问题求解

问题根因

该问题由FMX LiveBindings框架的类型转换机制导致:框架默认未注册第三方DAC返回的TBcd/Currency类型到字符串的转换逻辑。
FireDAC作为官方内置数据访问组件,在单元初始化阶段已经自行注册了所有配套字段类型的绑定转换器,因此金额字段可以正常显示;第三方DAC(包括Advantage数据库组件、ElevateDB组件等)未主动添加该注册逻辑时,LiveBindings会直接调用类型的默认ToString方法,最终渲染出"(BCD)"文本,问题和数据集本身的取值逻辑无关,不需要迁移到VCL架构。
以下三种方案均可解决问题,按推荐优先级排序:

方案一:全局注册类型转换器(最推荐)

该方案一次配置即可全项目生效,对现有业务代码无侵入,不需要修改任何数据集、网格控件的现有配置,兼容所有数据访问组件。

  • 代码中引用必要单元:System.Rtti、Data.Bind.Components、Data.FmtBcd
  • 编写转换器注册方法,在程序启动阶段(主窗体OnCreate事件、或项目初始化段)执行一次即可:
procedure RegisterBCDBindingConverters;
var
  LConverter: TBindingConverter;
  LRttiCtx: TRttiContext;
begin
  LRttiCtx := TRttiContext.Create;
  // 注册TBcd类型到字符串的转换
  LConverter := TBindingConverter.Create;
  LConverter.SourceType := LRttiCtx.GetType(TypeInfo(TBcd));
  LConverter.TargetType := LRttiCtx.GetType(TypeInfo(string));
  LConverter.ConvertProc := procedure(InValue: TValue; out OutValue: TValue)
  var
    LBcdVal: TBcd;
  begin
    if InValue.TryAsType<TBcd>(LBcdVal) then
      // 如需自定义金额格式(保留小数位、千分位等),可替换为BcdToStrF
      OutValue := BcdToStr(LBcdVal)
    else
      OutValue := string.Empty;
  end;
  TBindingManager.Default.RegisterConverter(LConverter);

  // 注册Currency类型到字符串的转换
  LConverter := TBindingConverter.Create;
  LConverter.SourceType := LRttiCtx.GetType(TypeInfo(Currency));
  LConverter.TargetType := LRttiCtx.GetType(TypeInfo(string));
  LConverter.ConvertProc := procedure(InValue: TValue; out OutValue: TValue)
  var
    LCurrVal: Currency;
  begin
    if InValue.TryAsType<Currency>(LCurrVal) then
      // 如需自定义金额格式,可替换为CurrToStrF
      OutValue := CurrToStr(LCurrVal)
    else
      OutValue := string.Empty;
  end;
  TBindingManager.Default.RegisterConverter(LConverter);
end;

方案二:单网格自定义绘制

如果不希望修改全局绑定规则,仅需要对特定TGrid控件生效,可以通过网格的OnDrawColumnCell事件手动处理BCD/Currency字段的渲染逻辑:

uses
  Data.DB, Data.FmtBcd;

procedure TMainForm.Grid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas;
  const Column: TColumn; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
var
  LBindField: TField;
  LDisplayText: string;
begin
  LBindField := Column.Link.ExpressionSource.GetObject as TField;
  if not Assigned(LBindField) then Exit;

  if LBindField is TBCDField then
  begin
    LDisplayText := BcdToStr(LBindField.AsBcd);
    Canvas.Fill.Color := TGrid(Sender).TextSettings.FontColor;
    Canvas.FillText(Bounds, LDisplayText, False, 1, [], TTextAlign.Leading, TTextAlign.Center);
    Column.DefaultDraw := False;
  end
  else if LBindField is TCurrencyField then
  begin
    LDisplayText := CurrToStr(LBindField.AsCurrency);
    Canvas.Fill.Color := TGrid(Sender).TextSettings.FontColor;
    Canvas.FillText(Bounds, LDisplayText, False, 1, [], TTextAlign.Leading, TTextAlign.Center);
    Column.DefaultDraw := False;
  end;
end;

该方案可以灵活控制单元格的字体、对齐方式、文本颜色等显示样式,适配个性化展示需求。

方案三:字段级事件处理

如果项目中数据集数量少、字段固定,可以为对应数据集添加持久化字段,给BCD/Currency字段编写OnGetText事件手动返回显示文本:

procedure TMainForm.TableAmountFieldGetText(Sender: TField; var Text: string;
  DisplayText: Boolean);
begin
  if Sender is TBCDField then
    Text := BcdToStr(Sender.AsBcd)
  else if Sender is TCurrencyField then
    Text := CurrToStr(Sender.AsCurrency);
end;

该方案需要逐个为对应字段绑定事件,适配成本较高,仅推荐小型固定字段项目使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:45:19