设计时属性的值,不会出现在运行时

Posted

技术标签:

【中文标题】设计时属性的值,不会出现在运行时【英文标题】:Values of a property at design time, doesn't appear at run time 【发布时间】:2013-05-22 15:31:56 【问题描述】:

我有以下组件,其中包含从自定义类派生的属性:

unit MyComponentTest3;

interface

uses  Windows, ExtCtrls,Classes,Controls;

type

  TMyClass3 = class
    myString: string;
    myNumber: double;
  end;

  TMyComponentTest3 = class(TCustomPanel)
  private
    FMyProperty: TMyClass3;

    procedure SetMyProperty(Value: TMyClass3);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure SetMyPropertyPublic(AmyString: string; AmyNumber: double);
  published
    property MyProperty: TMyClass3 read FMyProperty write SetMyProperty;
  end;

procedure Register;

implementation


procedure Register;
begin
  RegisterComponents('MyComponents', [TMyComponentTest3]);
end;

 TMyComponentTest3 

constructor TMyComponentTest3.Create(AOwner: TComponent);
begin
  inherited;

  FMyProperty:= TMyClass3.Create;

end;

destructor TMyComponentTest3.Destroy;
begin
  FMyProperty.Free;

  inherited;
end;

procedure TMyComponentTest3.SetMyProperty(Value: TMyClass3);
begin
with FMyProperty do
  begin
    myString:= Value.myString;
    myNumber:= Value.myNumber;
  end;
end;

procedure TMyComponentTest3.SetMyPropertyPublic(AmyString: string;
  AmyNumber: double);
var
  auxMyProperty: TMyClass3;
begin

  auxMyProperty:= TMyClass3.Create;

  with auxMyProperty do
  begin
    myString:= AmyString;
    myNumber:= AmyNumber;
  end;

  SetMyProperty(auxMyProperty);

  auxMyProperty.Free;

end;

end.

它工作正常,但是当我在设计时设置属性的值并运行程序时,值消失了。如果我设置组件的值,保存所有内容,当我加载这些值时,我会遇到同样的问题......

我想问题是因为我一直在创建自定义类的实例,但我不确定,也不知道如何解决这个问题。有人知道我能做什么吗?

【问题讨论】:

有什么理由不让TMyClass3 成为记录而不是类? 这只是一个简单的例子,在我的真实代码中它更复杂...... @J... 不管它有多复杂,关键的决定因素是你想要值还是引用赋值语义。 【参考方案1】:

TMyClass3 需要派生自 TPersistent 才能在 DFM 中进行流式传输。它还应该选择性地覆盖虚拟的Assign() 方法,然后SetMyProperty() 将能够调用该方法。

试试这个:

unit MyComponentTest3;

interface

uses
  Windows, ExtCtrls, Classes, Controls;

type

  TMyClass3 = class(TPersistent)
  private
    FMyString: string;
    FMyNumber: double;
  public
    procedure Assign(Source: TPersistent); override;
  published 
    property myString: string read FMyString write FMyString;
    property myNumber: double read FMyNumber write FMyNumber;
  end;

  TMyComponentTest3 = class(TCustomPanel)
  private
    FMyProperty: TMyClass3;

    procedure SetMyProperty(Value: TMyClass3);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure SetMyPropertyPublic(AmyString: string; AmyNumber: double);
  published
    property MyProperty: TMyClass3 read FMyProperty write SetMyProperty;
  end;

procedure Register;

implementation


procedure Register;
begin
  RegisterComponents('MyComponents', [TMyComponentTest3]);
end;

 TMyClass3 

procedure TMyClass3.Assign(Source: TPersistent);
begin
  if Source is TMyClass3 then
  begin
    with TMyClass3(Source) do
    begin
      Self.FMyString := myString;
      Self.FMyNumber := myNumber;
    end;
  end else
    inherited;
end;

 TMyComponentTest3 

constructor TMyComponentTest3.Create(AOwner: TComponent);
begin
  inherited;
  FMyProperty := TMyClass3.Create;
end;

destructor TMyComponentTest3.Destroy;
begin
  FMyProperty.Free;
  inherited;
end;

procedure TMyComponentTest3.SetMyProperty(Value: TMyClass3);
begin
  FMyProperty.Assign(Value);
end;

procedure TMyComponentTest3.SetMyPropertyPublic(AmyString: string; AmyNumber: double);
begin
  with MyProperty do
  begin
    myString := AmyString;
    myNumber := AmyNumber;
  end;  
end;

end.

【讨论】:

没什么...它似乎没有到达这个分配过程,值仍然没有出现在运行时,我在分配过程中放了一条消息来检查它从来没有显示它 Assign() 不会被调用,因为在 DFM 流式传输期间不会调用属性设置器。这个建议只是为了清理你的设置器并实现更好的封装。您的问题是另外一回事,但您仍然需要从基础开始 - 从TPersistent 派生,使子值本身成为已发布的属性等。您所描述的表明这些值并没有被保存到 DFM 开始,因此不存在以供稍后加载。 在设计时测试组件的 DFM 流功能的一种简单方法是将组件拖放到表单上,根据需要设置属性,右键单击表单设计器并选择“以文本形式查看”并验证值是否存在,然后再次右键单击并选择“以表单查看”并验证值是否在组件中。如果您的值没有按预期工作,那么某些东西就坏了。 只有发布的属性会和组件一起保存?我有一个属性,它是一个数组,我不能发布它,但是我需要保存它的值......你知道怎么做吗? 是的,默认情况下,只有使用支持的数据类型的 published 属性会被流式传输。要流式传输其他数据,您需要覆盖虚拟DefineProperties() 方法以提供自定义流式传输。【参考方案2】:
constructor TMyComponentTest3.Create(AOwner: TComponent);
begin
  inherited;
  FMyProperty := TMyClass3.Create;
  FMyProperty.SetSubComponent(True);
end;

【讨论】:

以上是关于设计时属性的值,不会出现在运行时的主要内容,如果未能解决你的问题,请参考以下文章

DirectX 11:运行简单的 DirectX 应用程序时运行时崩溃

为啥 Kubernetes 的容器在 runsc (gVisor) 上作为 Docker 中的运行时运行时会失败?

使用ActiveSheet.Range时运行时错误13“类型不匹配”

表名正确时运行时错误3078

Algs4-1.4.41运行时间

添加新对象时运行时覆盖列表元素[重复]