Introduction
There are some special dataset application where you might need to know when
a dataset is made active or inactive through a change to the Active property.
My project required a dataset which created a physical table when the component
was instantiated, said table to be destroyed when the component was destroyed.
Under normal circumstances, one looks for a method whose name is Set<propertyname>
to override for the purpose of trapping changes to the property. However, the
TDataSet class is non-orthogonal in that a table can be opened both by setting
the Active property or calling the Open method. For this reason, a method called
InternalOpen is shared by both SetActive() and Open().
A chapter in the "Delphi Developer's Handbook" discusses establishing new classes
derived from TCustomDataSet, and it recommends overriding the InternalOpen method.
However, my table class is derived from a third party descendant of TTable and,
for whatever reason, it seems to override the OpenCursor method rather than
InternalOpen. I therefore chose to follow their lead.
The Implementation
The implementation overrides the void __fastcall OpenCursor(bool theInfoQuery)
and void __fastcall CloseCursor(void) methods.
Because this component creates a table when it is instantiated and made active,
I do not allow it to be made active at design time. This is done by...
if (ComponentState.Contains(csDesigning)) // Can't open at
design time, which would create a table
{
SetState(dsInactive);
return;
}; |
One must be careful because there are certain operations which provoke a call
to OpenCursor, and if you perform them, you will end up with an endless recursive
loop (BatchMove is one of these methods). If you must call one of these methods,
bracket the call with a guard variable to prevent recalling that method until
the operation is complete, for instance:
if (!myCopyInProgress)
{
myCopyInProgress = true;
BatchMove(OtherTable,batCopy);
myCopyInProgress = false;
};
Inherited::OpenCursor(theInfoQuery); |
which basically passes the batch move OpenCursor() to the inherited method.
The "myCopyInProgress" variable should be initialized in the constructor to
false, so that the first call (and subsequent calls) to OpenCursor() will perform
the needed operations.
Closing the cursor in my project required me to delete the created physical
table, so I needed to override CloseCursor and to check to make sure the table
was being closed because the component was being destroyed (ComponentState.Contains(csDestroying))
before deleting the table. You may or may not have a need to override that method.
Once again, remember to call the inherited method from your method.
Conclusion
You may never need to create a class such as this, but if you do, you will
not find it so difficult if you follow the steps shown above.
|