2013-10-31 13 views
5

Mi piace disabilitare i controlli quando è inutile che l'utente faccia clic su di essi.Come implementare IsFirstRecord e IsLastRecord?

Un caso speciale è un insieme di pulsanti di menu personalizzati che emulano i pulsanti primo, precedente, successivo e ultimo di uno standard TDBNavigator.

Quando l'utente fa clic sul primo pulsante, i pulsanti primo e precedente sono entrambi disabilitati.

Quando l'utente fa clic sui pulsanti successivi e precedenti, lo TDataSet sottostante viene posizionato sullo stesso record di prima, ma i pulsanti primo e precedente sono entrambi ancora abilitati.

L'implementazione corrente si presenta così:

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 e Eof non sono il modo giusto per disabilitare i pulsanti, perché devo sapere in anticipo se il record corrente sta per essere il primo/ultimo record .

così ho pensato di riscrivere questo utilizzando un IsFirstRecord e IsLastRecord metodo:

function IsFirstRecord(ADataSet: TDataSet): Boolean; 
begin 
    Result := ADataSet.RecNo = 0; 
end; 

function IsLastRecord(ADataSet: TDataSet): Boolean; 
begin 
    Result := ADataSet.RecNo = ADataSet.RecordCount - 1; 
end; 

Non credo che questa sia una buona idea, dal momento che ho visto casi in cui per il primo record RecNo = 0 non è vero. (ad esempio una TADSQuery filtrata)

Che cos'è un'implementazione affidabile per IsFirstRecord e IsLastRecord? È persino possibile utilizzare l'attuale architettura TDataSet?

+0

'RecNo' è opzionale (può essere non implementato) per insiemi di dati SQL. 'RecordCount' è dannoso per il set di dati SQL, poiché richiede di recuperare tutti i dati. Immagina la richiesta SQL SELECT, che genera 10 GB di informazioni. Solitamente l'utente dovrebbe analizzare solo la prima schermata di dati (o forse 3 schermi o 10 schermi) e quindi chiudere il modulo, ignorando il resto di dati molto meno rilevanti. Chiamando .RecordCount si richiede che 1: SQL Server legga correttamente tutti quei 10 GB dai dischi 2: la rete trasferirà tutti quei 10 GB di dati 3: il client memorizzerà nella RAM tutti quei 10 GB di dati. –

+0

Quindi sarebbe stress-test per server e rete (rallentando tutti gli altri lavori) e per problemi di memoria sul client. E tutto questo per motivi di informazione che probabilmente non sarebbero mai necessari. Quindi l'approccio 'RecNo' è appropriato per i database ISAM (DBF, Paradox, ecc.). Per i database SQL il modo corretto è utilizzare le funzioni 'TDataSet.EOF' e' TDataSet.BOF' –

+1

PS. per definizione DataSet.Empty == DataSet.EOF e DataSet.BOF in modo che il controllo sia ridondante. Immagino tu intenda qualcosa 'DataSet.Active e non DataSet.Bof;' –

risposta

5

Si potrebbe provare qualcosa di simile:

function IsFirstRecord(ADataSet: TDataSet): Boolean; 
var 
    BmStr: TBookmarkStr; 
begin 
    Result := not ADataSet.IsEmpty; 
    if not Result then Exit; 
    Result := ADataSet.Bof; 
    // if ADataSet is already at BOF there is no point to continue 
    if not Result then 
    begin 
    ADataSet.DisableControls; 
    try 
     BmStr := ADataSet.Bookmark; 
     try 
     ADataSet.Prior; 
     Result := ADataSet.Bof; 
     finally 
     ADataSet.Bookmark := BmStr; 
     end; 
    finally 
     ADataSet.EnableControls; 
    end; 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if IsFirstRecord(ADODataSet1) then 
    ShowMessage('First') 
    else 
    ShowMessage('Not First'); 
end; 

Per IsLastRecord implementazione semplicemente sostituire:

ADataSet.Prior -> ADataSet.Next 
ADataSet.Bof -> ADataSet.Eof