Редактор коллекции не открывается для свойства TCollection в свойстве TPersistent - PullRequest
2 голосов
/ 08 августа 2011

У меня есть свойство настраиваемой коллекции, которое прекрасно работает, когда оно является прямым членом моего компонента.

Но я хочу переместить свойство коллекции в свойство TPersistent внутри моего компонента.И теперь возникает проблема, она не работает: двойной щелчок по свойству коллекции в инспекторе объектов обычно открывает редактор коллекции, но это больше не происходит.

Кулак всего - что я должен передатьконструктор свойства TPersistent?

TMyCollection = class(TCollection)
  constructor Create(AOwner: TComponent); // TMyCollection constuctor
  ...

Я не могу передать Self, поэтому я должен передать своего постоянного владельца?

constructor TMyPersistent.Create(AOwner: TComponent);
begin
  inherited Create;
  fOwner := AOwner;
  fMyCollection := TMyCollection.Create(AOwner); // hmmm... doesn't make sense
end;

Я думаю, что что-то упустил.Если вам нужно больше кода, просто прокомментируйте этот пост.

Da visualizationz

1 Ответ

9 голосов
/ 08 августа 2011

Конструктор TCollection не требует TComponent, но TCollectionItemClass.

Ваша коллекция теперь является членом свойства TPersistent вместо того, чтобы быть непосредственным членом компонента, не имеет значения для конструктора.


Обновление

Чем отличается владение, тем не менее на уровне TPersistent, который должен управляться правильной реализацией GetOwner:

GetOwner возвращает владельца объекта. GetOwner используется методом GetNamePath для поиска владельца постоянного объекта. GetNamePath и GetOwner представлены в TPersistent, поэтому потомки, такие как коллекции, могут появляться в Инспекторе объектов.

Вы должны сообщить IDE, что ваше свойство TCollection принадлежит свойству TPersistent, которое, в свою очередь, принадлежит компоненту.

Учебное пособие, которое вы используете , содержит несколько ошибок относительно этой реализации:

  • Владелец коллекции объявлен как TComponent, который должен быть TPersistent,
  • GetOwner не реализован для класса свойств TPersistent, а
  • Исправление , показанное в конце учебника, утверждающее, что свойство TPersistent должно наследоваться от TComponent, совершенно неверно; или, если говорить точнее, это скорее обходной путь для отказа от реализации GetOwner.

Вот как это должно выглядеть:

unit MyComponent;

interface

uses
  Classes, SysUtils;

type
  TMyCollectionItem = class(TCollectionItem)
  private
    FStringProp: String;
  protected
    function GetDisplayName: String; override;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property StringProp: String read FStringProp write FStringProp;
  end;

  TMyCollection = class(TCollection)
  private
    FOwner: TPersistent;
    function GetItem(Index: Integer): TMyCollectionItem;
    procedure SetItem(Index: Integer; Value: TMyCollectionItem);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TPersistent);
    function Add: TMyCollectionItem;
    function Insert(Index: Integer): TMyCollectionItem;
    property Items[Index: Integer]: TMyCollectionItem read GetItem
      write SetItem;
  end;

  TMyPersistent = class(TPersistent)
  private
    FOwner: TPersistent;
    FCollectionProp: TMyCollection;
    procedure SetCollectionProp(Value: TMyCollection);
  protected
    function GetOwner: TPersistent; override;
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TPersistent);
    destructor Destroy; override;
  published
    property CollectionProp: TMyCollection read FCollectionProp
      write SetCollectionProp;
  end;

  TMyComponent = class(TComponent)
  private
    FPersistentProp: TMyPersistent;
    procedure SetPersistentProp(Value: TMyPersistent);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property PersistentProp: TMyPersistent read FPersistentProp
      write SetPersistentProp;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMyComponent]);
end;

{ TMyCollectionItem }

procedure TMyCollectionItem.Assign(Source: TPersistent);
begin
  if Source is TMyCollectionItem then
    FStringProp := TMyCollectionItem(Source).FStringProp
  else
    inherited Assign(Source);
end;

function TMyCollectionItem.GetDisplayName: String;
begin
  Result := Format('Item %d',[Index]);
end;

{ TMyCollection }

function TMyCollection.Add: TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited Add);
end;

constructor TMyCollection.Create(AOwner: TPersistent);
begin
  inherited Create(TMyCollectionItem);
  FOwner := AOwner;
end;

function TMyCollection.GetItem(Index: Integer): TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited GetItem(Index));
end;

function TMyCollection.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TMyCollection.Insert(Index: Integer): TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited Insert(Index));
end;

procedure TMyCollection.SetItem(Index: Integer; Value: TMyCollectionItem);
begin
  inherited SetItem(Index, Value);
end;

{ TMyPersistent }

procedure TMyPersistent.Assign(Source: TPersistent);
begin
  if Source is TMyPersistent then
    CollectionProp := TMyPersistent(Source).FCollectionProp
  else
    inherited Assign(Source);
end;

constructor TMyPersistent.Create(AOwner: TPersistent);
begin
  inherited Create;
  FOwner := AOwner;
  FCollectionProp := TMyCollection.Create(Self);
end;

destructor TMyPersistent.Destroy;
begin
  FCollectionProp.Free;
  inherited Destroy;
end;

function TMyPersistent.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TMyPersistent.SetCollectionProp(Value: TMyCollection);
begin
  FCollectionProp.Assign(Value);
end;

{ TMyComponent }

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FPersistentProp := TMyPersistent.Create(Self);
end;

destructor TMyComponent.Destroy;
begin
  FPersistentProp.Free;
  inherited Destroy;
end;

procedure TMyComponent.SetPersistentProp(Value: TMyPersistent);
begin
  FPersistentProp.Assign(Value);
end;

end.

Но могу ли я сказать, что вы также можете наследовать от TOwnedCollection, что значительно упрощает использование и объявление TMyCollection:

  TMyCollection = class(TOwnedCollection)
  private
    function GetItem(Index: Integer): TMyCollectionItem;
    procedure SetItem(Index: Integer; Value: TMyCollectionItem);
  public
    function Add: TMyCollectionItem;
    function Insert(Index: Integer): TMyCollectionItem;
    property Items[Index: Integer]: TMyCollectionItem read GetItem
      write SetItem;
  end;
...