I created TOwnedCollection
/ TCollectionItem
pair which tries to keep a TFmxObject
as one of its streaming properties. However, the TFmxObject
(FMyObject) does not stream in code when saved.
TMyItem = class(TCollectionItem)
private
FName: string;
FMyObject: TMyObject;
public
constructor Create(Collection: TCollection); overload; override;
destructor Destroy; override;
published
property Name: string read FName write FName;
property MyObject: TMyObject read FMyObject write FMyObject;
end;
// TMyItems CLASS not shown as it is standard code
TMyObject = class(TFmxObject)
private var
FObjectName: string;
published
property ObjectName : string read FObjectName write FObjectName;
end;
///////////////////////////////////////////////////////
implementation
constructor TMyItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
FMyObject := TMyObject.Create(nil); // note: TMyObject.Create(self) will not work
end;
destructor TMyItem.Destroy;
begin
FMyObject.Free;
inherited Destroy;
end;
Inside the streaming information, despite setting TMyObject.ObjectName, TMyObject is not streamed into MyItems (i.e. ObjectName = 'Object1' is not streamed)
MyItems = <
item
Name = 'Test1'
end
item
Name = 'Test2'
end>
Sample code:
var oNewMyItem := [....]MyItems.Add('Test1');
oNewMyItem.MyObject.ObjectName := 'Object1'; // no errors or AV but does not stream
I need MyObject to be TFmxObject
as it is used elsewhere, but I need it to be "stream-able" in TMyItem's properties.
Thanks for any advice.
Since TMyItem
owns the FMyObject
object, but doesn't assign an Owner
to it, you need to make TMyItem.Create()
call FMyObject.SetSubComponent(true)
to stream it properly:
constructor TMyItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
// note: TMyObject.Create(self) will not work
FMyObject := TMyObject.Create(nil);
FMyObject.SetSubComponent(True); // <-- add this
end;
Also, your MyObject
property setter is writing directly to the FMyObject
member. If anyone were to assign a TMyObject
object to your property, it would overwrite that member leaking the original object that you create, and take ownership of the caller's object instead. Neither is correct behavior in this case. Your MyObject
property instead needs a setter method that calls FMyObject.Assign()
, eg:
TMyItem = class(TCollectionItem)
private
...
FMyObject: TMyObject;
procedure SetMyObject(AValue: TMyObject);
...
published
...
property MyObject: TMyObject read FMyObject write SetMyObject;
end;
procedure TMyItem.SetMyObject(AValue: TMyObject);
begin
FMyObject.Assign(AValue);
end;