'Differences in component streaming at runtime and design time
I have some code that works properly at runtime but not in the IDE. I am unable to find any documentation about how the loading of components is different that helps me.
I have developed some components that define resources. I have also developed a custom TDataModule descendant that holds these resource definitions. As I want to be able to share the definitions between projects I have a simple TComponent descendent that can embed a TDataModule within it - the idea being that dropping the appropriate TComponent on a form or data module includes all of the resource definitions on the embedded TDataModule.
This appears to be working as expected at run time, but not in the designer.
I will try to explain the operation as concisely as possible. There is lots of code involved but hopefully the following is enough to understand what's happening.
There is a global TDictionary for registering the resource definitions. The definitions are registered using a Binary UUID (a 16 byte array) as the key. The UUID of the resource is set as a string representation (for ease of streaming). When the string value is set the setter method checks on itself and upwards to see if it or any of the Owner TComponents match csLoading in ComponentState and if any do the string value is saved temporarily. If not the resource definition registers itself in the global dictionary. (This is necessary because a random UUID is assigned in AfterConstruction at which point the csLoading flag is not set and so the parents must be checked).
When a resource definition is fully streamed in the Loaded call the temporary string is used to set the UUID and the resource is registered.
The TComponent that includes a TDataModule of definitions is based on a root class which has the following template code:
type
TITIODataResourcesLoader = class(TDataModule)
...
end;
TITIODataResourcesLoaderClass = class of TITIODataResourcesLoader;
TITIOResourceInclusion = class(TComponent)
protected
_pResources: TITIODataResourcesLoader;
class function _GetModuleClass(): TITIODatResourcesLoaderClass; virtual; abstract;
public
destructor Destroy; override;
procedure AfterConstruction(); override;
end;
destructor TITIOResourceInclusion.Destroy;
begin
FreeAndNil(Self._pResources);
inherited;
end;
procedure TITIOResourceInclusio.AfterConstruction;
begin
Self._pResources:=Self._GetModuleClass().Create(Self);
inherited;
end;
I have component editors for many of the resources which allow selection of a resource by enumerating the Values in the global TDictionary for that class of resource. So, for example, one of the resource definition types is the definition of a database table and another of the resource definition types is the definition of a database table join. In the component editor for the definition of the join the user can chose which tables to join by selecting any of the tables that are registered in the global TDictionary.
In a test project that has a TITIODataResourcesLoader which defines a number of table types, and a TITIOResourceInclusion that includes another TITIODataResourcesLoader (which is in a different BPL file) then at runtime the join editor (which is a VCL Form) will show all of the tables, but in the designer only the tables which are defined on the test project's TITIODataResourcesLoader are available. If I open the TITIODataResourcesLoader included in the BPL file then the resources on that are registered and selectable in the designer on the test project's TITIODataResourcesLoader.
So it appears that at runtime the streaming of the TITIOResourceInclusion does not cause the components in the included TITIODataResourcesLoader to be registered, but at runtime it does work as expected.
So my question and confusion is: How is the streaming of components different in the Designer?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
