I like to disable controls when it's pointless for the user to click on them.
One special case is a set of custom menu buttons that emulate the first, prior, next and last buttons of a standard TDBNavigator
.
When the user clicks on the first button, the first and prior buttons are both disabled.
When the user then clicks the next and prior buttons the underlying TDataSet
is positioned on the same record as before, but the first and prior buttons are both still enabled.
The current implementation looks like this:
NavigationFirstButton.Enabled := not DataSet.IsEmpty and not DataSet.Bof;
NavigationPriorButton.Enabled := not DataSet.IsEmpty and not DataSet.Bof;
NavigationNextButton.Enabled := not DataSet.IsEmpty and not DataSet.Eof;
NavigationLastButton.Enabled := not DataSet.IsEmpty and not DataSet.Eof;
Bof
and Eof
are not the right way to disable the buttons, because I have to know beforehand if the current record is going to be the first/last record.
So I thought of rewriting this using a IsFirstRecord
and IsLastRecord
method:
function IsFirstRecord(ADataSet: TDataSet): Boolean;
begin
Result := ADataSet.RecNo = 0;
end;
function IsLastRecord(ADataSet: TDataSet): Boolean;
begin
Result := ADataSet.RecNo = ADataSet.RecordCount - 1;
end;
I don't think that this is a good idea, since I've seen cases where for the first record RecNo = 0
is not true. (i.e. A filtered TADSQuery)
What is a reliable implementation for IsFirstRecord
and IsLastRecord
? Is it even possible using the current TDataSet
architecture?
RecNo
is optional (may be non-implemented) for SQL datasets.RecordCount
is bad for SQL dataset, because it requires to fetch all the data. Imagine SQL SELECT request, that generates 10GB of information. Usually user would only analyze first screen of data (or maybe 3 screens or 10 screens) and then close the form, ignoring the rest of much less relevant data. By calling .RecordCount you demand that 1: SQL Server would read in proper order all those 10GB from discs 2: Network would transfer all those 10GB of data 3: client would cache in RAM all those 10 GB of data. – CaracasRecNo
approach is proper thing for ISAM databases (DBF, Paradox, etc). For SQL databases proper way is to useTDataSet.EOF
andTDataSet.BOF
functions – CaracasDataSet.Active and not DataSet.Bof;
– CaracasRecordCount
info, this makes my initial idea even more wrong ;). So you think that what I'm trying to do is not possible in an efficient way? – ComedienneTSQLDataSet
, for instance, tries to run aselect count
query.TADSQuery
, also, looks like doing the sane thing and counting the records at the server side. – PectoralisRecordCount
is unreliable with ReadCommitted isolation level. You may get 100, but actually fetching racords soon after found there are 105 or 95 of those – Caracas