I'll start by saying my previous experience with component design was limited to fixing minor bugs in a pretty standard collection of visual controls.
I am currently working on a project which uses a tree of TPersistent descendants to define, store and retrieve data. The top of this tree is a descendant of TComponent. It has a published property which is a descendant of TCollection. Here's a simplification of the structure:
TMyComponent = class(TComponent)
private
FMyCollection: TMyCollection;
published
property Items: TMyCollection read FMyCollection write FMyCollection;
end;
TMyCollection = class(TCollection)
protected
procedure SetItem(index: integer; val: TCompositeItem);
function GetItem(index: integer): TCompositeItem;
public
property Items[index: integer]: TCompositeItem read GetItem write SetItem; default;
end;
TCompositeItem = class(TCollectionItem)
private
FMyCollection: TMyCollection;
published
property Items: TMyCollection read FMyCollection write FMyCollection;
end;
There are at least a dozen descendants of TCompositeItem
. When you want to add a new item to the collection of one of the nodes in the tree you bring up the context menu and click "Add Item". This creates a new item which you must then further define as one one of the numerous descendants of TCompositeItem
using the Object Inspector.
This works relatively well. The problem is that changes to the tree in the designer are not reflected in the associated source file. To get around this my predecessor added some synchronization code that recreates declarations in the .pas file from the tree in the .dfm. To properly synchronize everything you have to save your changes in the dfm, then double-click the component on the form (which triggers the synchronization code), then save again. Additionally you can only do one synchronization per editing session otherwise you get a prompt telling you to close the form, reopen it, then do the synchronization. If you forget to follow this procedure all kinds of strange behaviors occur at run time. Its kind of awkward but it works.
What I would like to do is have changes in the designer automatically updated in the cached source file then saved as normal when the developer clicks save, eliminating the need for the awkward three step synchronization.
This is how normal controls work so I'm not really sure why it doesn't work with this one. I have a gut feeling that the reason may be related to the ultimate class for each item in a collection not being determined until after it is created in the designer. Any suggestions?
Update
Upon further investigation it looks like the synchronization code does two things:
- Edits the class definition of the form, adding published fields for each node in the tree.
- Edits a procedure called
InitializeComponents
, which assigns each node to one of the published fields.