To create a data aware component you are basically interfacing with a TFieldDataLink object. This controls the interaction with the BDE. In this example I'm going to make an edit box data aware. To do this I'm going to use two design patterns: Wrapper and Mediator. Here's the initial declaration:
type
TMyDBEdit = class( TEdit )
private
protected
FDataLink :
TFieldDataLink;
public
constructor
Create( AOwner : TComponent ); override;
destructor
Destroy; override;
end;
constructor TMyDBEdit.Create( AOwner : TComponent );
begin
inherited Create( AOwner );
FDataLink := TFieldDataLink.Create;
end;
destructor TMyDBEdit.Destroy;
begin
FDataLink.Free;
inherited Destroy;
end;
Straight forward enough so far. The first step is to surface the FieldName and DataSource properties of the FDataLink object. This is a classic Wrapper pattern.
type
TMyDBEdit = class( TEdit )
private
protected
FDataLink :
TFieldDataLink;
function
GetDataSource: TDataSource;
function
GetFieldName: string;
procedure
SetDataSource(Value: TDataSource);
procedure
SetFieldName(Value: string);
public
constructor
Create( AOwner : TComponent ); override;
destructor
Destroy; override;
published
property
DataSource: TDataSource read GetDataSource write SetDataSource;
property
FieldName: string read GetFieldName write SetFieldName;
end;
{the constructor and destructor are identical to before}
function TMyDBEdit.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
function TMyDBEdit.GetFieldName: string;
begin
Result := FDataLink.FieldName;
end;
procedure TMyDBEdit.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
end;
procedure TMyDBEdit.SetFieldName(Value: string);
begin
FDataLink.FieldName := Value;
end;
(This is a doddle). Right, the next bit is to write the Mediator pattern. This wires two events (OnDataChange and OnUpdateData) in FDataLink to procedures in TMyDBEdit.
type
TMyDBEdit = class( TEdit )
private
protected
FDataLink :
TFieldDataLink;
function
GetDataSource: TDataSource;
function
GetFieldName: string;
procedure
SetDataSource(Value: TDataSource);
procedure
SetFieldName(Value: string);
procedure
DataLinkDataChange(Sender: TObject);
procedure
DataLinkUpdateData(Sender: TObject);
procedure
UnwireDataLink;
procedure
WireDataLink;
public
constructor
Create( AOwner : TComponent ); override;
destructor
Destroy; override;
published
property
DataSource: TDataSource read GetDataSource write SetDataSource;
property
FieldName: string read GetFieldName write SetFieldName;
end;
procedure TMyDBEdit.WireDataLink;
begin
FDataLink.OnDataChange := DataLinkDataChange;
FDataLink.OnUpdateData := DataLinkUpdateData;
end;
procedure TMyDBEdit.UnwireDataLink;
begin
FDataLink.OnDataChange := nil;
FDataLink.OnUpdateData := nil;
end;
{Change the constructor and destructor to call these two
functions}
constructor TMyDBEdit.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FDataLink := TFieldDataLink.Create;
WireDataLink;
end;
destructor TMyDBEdit.Destroy;
begin
UnwireDataLink;
FDataLink.Free;
inherited Destroy;
end;
{Implement the wired functions}
procedure TMyDBEdit.DataLinkDataChange(Sender: TObject);
begin
if FDataLink.Field = nil then
Text := ''
else
Text := FDataLink.Field.AsString;
end;
procedure TMyDBEdit.DataLinkUpdateData(Sender: TObject);
begin
FDataLink.Field.AsString := Text;
end;
There's only one thing left to do and that's to implement the overriden Change procedure.
type
TMyDBEdit = class( TEdit )
private
protected
FDataLink :
TFieldDataLink;
function
GetDataSource: TDataSource;
function
GetFieldName: string;
procedure
SetDataSource(Value: TDataSource);
procedure
SetFieldName(Value: string);
procedure
DataLinkDataChange(Sender: TObject);
procedure
DataLinkUpdateData(Sender: TObject);
procedure
UnwireDataLink;
procedure
WireDataLink;
procedure Change;
override;
public
constructor
Create( AOwner : TComponent ); override;
destructor
Destroy; override;
published
property
DataSource: TDataSource read GetDataSource write SetDataSource;
property
FieldName: string read GetFieldName write SetFieldName;
end;
{Nothing else changes apart from this}
procedure TMyDBEdit.Change;
begin
FDataLink.Modified;
inherited Change;
end;
And, er, that's it.