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

嵌入TFDQuery的自定义控件无法将持久化字段保存至DFM

问题分析与解决方案

你遇到的核心问题是:自定义组件内部的TFDQuery子组件,其持久化字段无法保存到DFM文件,仅在表单类声明中生成字段代码,但无对应DFM对象。以下是具体原因和修复步骤:


核心原因

虽然你给FEntityData调用了SetSubcomponent(True),但设计器并未将它的持久化字段视为父组件的一部分进行持久化,主要遗漏了以下关键环节:

  1. 父组件未重写GetChildren和SetChildOrder方法,设计器无法枚举到内部子组件;
  2. EntityData属性的Assign方法默认不会复制持久化字段,且设计时子组件需要被设计器直接管理,而非通过赋值覆盖;
  3. 未标记子组件为持久化状态,设计器不会将其属性写入DFM。

具体修复步骤

1. 重写父组件的子组件枚举方法

设计器通过GetChildren和SetChildOrder识别组件的子组件,需要将内部的FEntityData和FEntityDatasource暴露给设计器:

type
  TKpDBEntityEdit = class(TdxPanel)
  private
    ...
  protected
    // 添加以下两个方法
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    procedure SetChildOrder(Child: TComponent; Order: Integer); override;
    ...
  public
    ...
  published
    ...
  end;

implementation

procedure TKpDBEntityEdit.GetChildren(Proc: TGetChildProc; Root: TComponent);
begin
  inherited;
  if FEntityData <> nil then Proc(FEntityData);
  if FEntityDatasource <> nil then Proc(FEntityDatasource);
end;

procedure TKpDBEntityEdit.SetChildOrder(Child: TComponent; Order: Integer);
begin
  if Child = FEntityData then
    FEntityData.Tag := Order
  else if Child = FEntityDatasource then
    FEntityDatasource.Tag := Order
  else
    inherited;
end;

2. 调整EntityData属性的实现逻辑

原SetEntityData的Assign操作会丢失设计时的持久化字段,建议改为只读属性(因为子组件由父组件创建管理),或调整赋值逻辑以保留字段:

// 方案1:改为只读属性(推荐,子组件由父组件内部创建)
published
  property EntityData: TFDQuery read FEntityData;
  property EntityDatasource: TDatasource read FEntityDatasource;

// 方案2:如果必须支持外部赋值,修改SetEntityData逻辑
procedure TKpDBEntityEdit.SetEntityData(const Value: TFDQuery);
begin
  if FEntityData <> Value then
  begin
    FEntityData.Assign(Value);
    // 手动复制持久化字段
    FEntityData.Fields.Clear;
    Value.Fields.AssignTo(FEntityData.Fields);
    // 通知设计器组件已修改
    if csDesigning in ComponentState then
      (Owner as IDesigner).Modified;
  end;
end;

3. 标记子组件为持久化状态

在创建FEntityData时,添加持久化标记,确保设计器将其属性写入DFM:

constructor TKpDBEntityEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ...
  FEntityData := TFDQuery.Create(Self);
  FEntityData.Name := Self.Name + 'qEntity';
  FEntityData.SetSubComponent(True);
  // 添加此行,标记为持久化组件
  FEntityData.ComponentState := FEntityData.ComponentState + [csPersistent];
  ...
end;

4. 调整ComponentEditor的字段编辑器调用逻辑

确保设计器能正确识别子组件的归属:

procedure TkpEntityEditEditor.ExecuteVerb(Index: Integer);
var
  EntityEdit: TKpDBEntityEdit;
begin
  EntityEdit := TKpDBEntityEdit(Component);
  case Index of
    0: 
      begin
        // 确保子组件已被设计器注册
        if EntityEdit.EntityData.Owner = EntityEdit then
          Designer.AddComponent(EntityEdit.EntityData);
        ShowFieldsEditor(Designer, EntityEdit.EntityData, TDSDesigner);
      end;
  end;
end;

额外检查点

  • 若TKpQuery是TFDQuery的自定义子类,确保其正确继承了父类的持久化字段处理逻辑;
  • 检查IDE的DFM保存设置,确保启用了"保存子组件属性"选项;
  • 添加字段后关闭并重新打开表单,验证DFM文件是否已生成字段的持久化代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:11:03