Mattias Gaertner wrote 22 lines
> [...]
> Thanks, I think I found a better way.
>
> The outer container has no nested components of it's own. It seems I
> can hook into (override) TComponent.WriteState which is calling
> WriteComponentData (properties, then Children). Since no children are
> there, I can make my own calls to WriteComponent from there,
> supplying all the components, of all the helper objects.
>
> On Read, I can Hook into ReadState. I can let the reader add them
> normally, and sort them out/once they have been read by the reader.
>
> The remaining question is: Does that look like something that will
> stay compatible with future code? The generated LFM file definitely
> looks like any LFM file (it has a component, with properties first
> then other nested Components)
>
To store a property that is a component and which is not owned by the
Lookuproot (form, datamodule, frame) you must set the csSubComponent
flag in ComponentStyle.
yes, I found the csSubComponent. But it stores the only the properties of the SubComponent, not the Component's Class.
SubComponent does (Within the list of properties of the actual component): MySubCompProp.Value1 = 120
MySubCompProp.Foo = 'abc'
And also subcomps, look (correctly) at the definition of the property. It the Property is defined as TFoo (" property mySubCompProp: TFoo reads FMyFoo write FMyFoo;" , then all properties known by this class (TFoo) are stored. In My case the actual Object may be a descend and of TFoo (that is the objects stored in FMyFoo), and have additional Properties (This additional Properties would be lost)
My Components are in a TList, the have different classes, so I need to save them the same way like nested components:
object MySubCompFromListClassABC: TSubCompClassABC Value1 = 120
end;
The Real Background is SynEdits Gutter.
The Gutter, I have managed to get saved. (via csSubComponent). But then the Gutter has a list of GutterParts (all of them Objects (and I can/will make them Components)). I need to save all those GutterParts. [ I know, I will also need a Property Editor for the object inspector, but that's not the issue ]
If A Gutter is created, with a new SynEdit, and *not* loaded from LFM; then it creates a default set.
If it is loaded, it needs to remove the default set (can be done in ReadState of SynEdit (SynEdit can inform the gutter) / Can depend on The LCL Version, so loading a 0.9.26 form, will keep the defaults, as no saved parts can exist)
To store a list use TCollection. If you can not use TCollection please
explain why not.
Because All collection Items a of the same class. If I make that TGutterPartBase, then only properties exposed by TGutterPartBase are saved. but each GutterPart has additional published properties. (Same applies, if I make the CollectionItem a wrapper class with a property "property TheRealGutterPart: TGutterPartBase" => because as csSubComponen it does not save the class-info)
Also even If I manage to get this subclasses into the collection (which is hard enough, as it is not supposed to be), If the collection is loaded, it restores them all to the base class, because it never saved the class-info
To store data of arbitrary length/format, use DefineProperties. This
has a drawback: In case of an error the IDE can not help fixing it.
DefineProperties only takes simple values. Because in define properties I must give it the name. Then In Read/WriteProc I deal with the value. So define Property will always create an LFM entry like: MyDefinedPropertyName = xxx
xxx Comes from the writecallback.
If the write callback attempts to do WriteComponent, then this will fail later, when the binary format is translated into text-lfm-format (because " MyDefinedPropertyName = MyObject: TMyClass" is not allowed
That is even, if the WriteCallback starts a list first, it will still fail. MyDefinedPropertyName = (
MyObject: TMyClass
....
With "DefineProperties" I have 2 (undesirable) possibilities:
1) use DefineBinarryProperties => and write my own format, no one can edit it, and why invent the wheel again?
2) use DefineProperties and define a large set of properties:
- define a classname property for each of my objects
- and define a property for each value that each of my objects needs to store.
Again there is code (WriteComponent) that does streaming of objects including class info; why invent the wheel again?
---------------
So as I see it I found 2 possibilities
1) The GutterParts are created as components owned by the SynEdit (or does it have to be the form; if it does have to be the form then there will be issues if there is more than one synedit.... ). that will be a lot of easy to break maintenance work. because you need to search through the component list to find the Objects.
And when loading I still need to remove the Objects created in Synedit.Create or I get double entries.
- Also I tried it, and SynEdit did not seem to stream them (MyGutterPart := TcomponentBasedClass.Create(TheSynEditAsOwner);) => nothing in the lfm
2) Maintain the objects as they are, but use SynEdit.WriteState to append them to the lfm
(They can easily be caught, if they get read (by the default reader) during loading
Best Regards
Martin