Quando in un form serve mostrare, accanto a un codice cliente o a un ID categoria, la relativa descrizione testuale, la soluzione più immediata è una DBLookupComboBox. Ma se quel valore va solo visualizzato — mai modificato dall'utente — un componente più leggero e a prova di click accidentale è una TLabel resa data-aware, che si aggiorna da sola quando il record corrente cambia.
Il meccanismo: TFieldDataLink
Il collegamento a un dataset in Delphi passa quasi sempre da un TFieldDataLink: si registra un gestore per l'evento OnDataEvent e si reagisce a deFieldChange, l'evento che scatta quando il valore del campo osservato cambia (nuovo record, modifica, scroll).
unit uCustomLookupLabel;
interface
uses
System.SysUtils, System.Classes, Vcl.StdCtrls, Data.DB, Vcl.DBClient;
type
TCustomLookupLabel = class(TLabel)
private
FDataLink: TFieldDataLink;
FLookupDataset: TClientDataSet;
FLookupKeyField: string;
FLookupResultField: string;
procedure DataEvent(Event: TDataEvent; Info: NativeInt);
function GetDataSource: TDataSource;
procedure SetDataSource(Value: TDataSource);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property LookupDataset: TClientDataSet read FLookupDataset write FLookupDataset;
property LookupKeyField: string read FLookupKeyField write FLookupKeyField;
property LookupResultField: string read FLookupResultField write FLookupResultField;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property DataField: string read GetDataField write SetDataField;
end;
implementation
constructor TCustomLookupLabel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDataLink := TFieldDataLink.Create;
FDataLink.OnDataEvent := DataEvent;
end;
destructor TCustomLookupLabel.Destroy;
begin
FDataLink.Free;
inherited;
end;
procedure TCustomLookupLabel.DataEvent(Event: TDataEvent; Info: NativeInt);
begin
if (Event = deFieldChange) and Assigned(FDataLink.Field) then
begin
if not FDataLink.Field.IsNull and Assigned(FLookupDataset) and
FLookupDataset.Locate(FLookupKeyField, FDataLink.Field.AsVariant, []) then
Caption := FLookupDataset.FieldByName(FLookupResultField).AsString
else
Caption := '';
end;
end;
function TCustomLookupLabel.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TCustomLookupLabel.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
if Value <> nil then
Value.FreeNotification(Self);
end;
end.Una variante senza dataset di lookup
Non sempre conviene tenere aperto un secondo dataset solo per una manciata di coppie chiave-descrizione (uno stato, una categoria, un tipo documento). In questi casi lo stesso meccanismo può appoggiarsi a un array in memoria di coppie TPair<Integer, string> invece che a un TClientDataSet: la logica di DataEvent resta identica, cambia solo il modo in cui si cerca il valore corrispondente (un ciclo for..in sull'array al posto di Locate).
Registrarlo in palette
Aggiungendo una procedure Register che chiama RegisterComponents, il componente diventa disponibile nella palette dell'IDE come qualsiasi altro controllo VCL, pronto per essere trascinato su un form e collegato a DataSource, DataField e LookupDataset direttamente a design time — senza una riga di codice nel form che lo ospita.