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
相关产品推荐
相关产品推荐

