delphi – 如何正确地流式传输子组件的TCollection属性,例如:嵌入式TDBGrid的Columns属性

前端之家收集整理的这篇文章主要介绍了delphi – 如何正确地流式传输子组件的TCollection属性,例如:嵌入式TDBGrid的Columns属性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直试图将另一个q的作者发给我的一些代码归结为MCVE
说明自定义组件的问题.

该组件只是一个TPanel后代,其中包含一个嵌入式TDBGrid.
我的源代码版本和测试项目如下.

问题是如果使用持久列创建嵌入式DBGrid,
当在IDE中重新打开其测试项目时,会引发异常

Error reading TColumn.Grid.Expanded. Property Griddoes not exist.

执行测试项目的Stream方法显示了如何出现此问题:

为了进行比较,我的表单上还有一个普通的TDBGrid,DBGrid1.而此DBGrid1的列被流式传输为

Columns = <
  item
    Expanded = False
    FieldName = 'ID'
    Visible = True
  end
[...]

嵌入式网格的列像这样流式传输

Grid.Columns = <
  item
    Grid.Expanded = False
    Grid.FieldName = 'ID'
    Grid.Visible = True
  end
[...]

它显然是Grid.Expanded的Grid前缀以及导致问题的其他列属性.

我想这个问题与DBGridColumns这个事实有关
是一个TCollection后代,嵌入式网格不是顶级对象
DFM.

我的问题是:如何修改TMyPanel的代码以便网格
列是否正确流式传输?

组件来源:

unit MAGridu;

interface

uses
  Windows,SysUtils,Classes,Controls,ExtCtrls,DBGrids;

type
  TMyPanel = class(TPanel)
  private
    FGrid : TDBGrid;
  public
    constructor Create(AOwner : TComponent); override;
  published
    property Grid : TDBGrid read FGrid;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard',[TMyPanel]);
end;

constructor TMyPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := TDBGrid.Create(Self);
  FGrid.SetSubcomponent(True);
  FGrid.Parent := Self;
end;

end.

测试项目来源:

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    CDS1: TClientDataSet;
    DataSource1: TDataSource;
    MyPanel1: TMyPanel;
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure Stream;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Stream;
end;

procedure TForm1.Stream;
//  This method is included as an easy way of getting at the contents of the project's
//  DFM.  It saves the form to a stream,and loads it into a memo on the form.
var
  SS : TStringStream;
  MS : TMemoryStream;
  Writer : TWriter;
begin
  SS := TStringStream.Create('');
  MS := TMemoryStream.Create;
  Writer := TWriter.Create(MS,4096);

  try
    Writer.Root := Self;
    Writer.WriteSignature;
    Writer.WriteComponent(Self);
    Writer.FlushBuffer;
    MS.Position := 0;
    ObjectBinaryToText(MS,SS);
    Memo1.Lines.Text := SS.DataString;
  finally
    Writer.Free;
    MS.Free;
    SS.Free;
  end;
end;
end.

procedure TForm1.FormCreate(Sender: TObject);
var
  Field : TField;
begin
  Field := TIntegerField.Create(Self);
  Field.FieldName := 'ID';
  Field.FieldKind := fkData;
  Field.DataSet := CDS1;

  Field := TStringField.Create(Self);
  Field.FieldName := 'Name';
  Field.Size := 20;
  Field.FieldKind := fkData;
  Field.DataSet := CDS1;

  CDS1.CreateDataSet;
  CDS1.InsertRecord([1,'One']);

end;

end.

解决方法

似乎你无能为力.当您查看过程WriteCollectionProp(TWriter.WriteProperties的本地)时,您会看到在调用WriteCollection之前清除了FPropPath.

TDBGrid或更好的TCustomDBGrid的问题在于,集合被标记为存储为false,并且流被委托给DefineProperties,后者使用TCustomDBGrid.WriteColumns来完成工作.

检查该方法会发现,尽管它也调用了WriteCollection,但FPropPath的内容之前并未清除.由于FPropPath是一个私有字段,因此有些预期.

它仍然适用于标准用例的原因是,在编写时,FPropPath只是空的.

由于Delphi 10.1柏林的行为与Delphi 7相同,我建议仅与此示例一起提交QP报告.

猜你在找的Delphi相关文章