When you write a Delphi database program, you generally connect some data-aware controls to a DataSource component, and then connect the DataSource component to a dataset. The connection between the data-aware control and the DataSource is called a data link and is represented by an object of class TDataLink or descendant. The data-aware control creates and manages this object and represents its only connection to the data. From a more practical perspective, to make a component data-aware, you need to add a data link to it and surface some of the properties of this internal object, such as the DataSource and DataField properties.
Delphi uses the DataSource and DataLink objects for bidirectional communication. The dataset uses the connection to notify the data-aware controls that new data is available (because the dataset has been activated, or the current record has changed, and so on). Data-aware controls use the connection to ask for the current value of a field or to update it, notifying the dataset of this event.
The relations among all these components are complicated by the fact that some of the connections can be one-to-many. For example, you can connect multiple data sources to the same dataset, you generally have multiple data links to the same data source (simply because you need one link for every data-aware component), and in most cases you connect multiple data-aware controls to each data source.
We'll work for much of this chapter with TDataLink and its derived classes, which are defined in the DB unit. This class has a set of protected virtual methods, which have a role similar to events. They are "almost-do-nothing" methods you can override in a specific subclass to intercept user operations and other data-source events. Here is a list, extracted from the class's source code:
type TDataLink = class(TPersistent) protected procedure ActiveChanged; virtual; procedure CheckBrowseMode; virtual; procedure DataSetChanged; virtual; procedure DataSetScrolled(Distance: Integer); virtual; procedure FocusControl(Field: TFieldRef); virtual; procedure EditingChanged; virtual; procedure LayoutChanged; virtual; procedure RecordChanged(Field: TField); virtual; procedure UpdateData; virtual;
All these virtual methods are called by the DataEvent private method, which is a sort of window procedure for a data source, triggered by several data events (see the TDataEvent enumeration). These events originate in the dataset, fields, or data source, and are generally applied to a dataset. The DataEvent method of the dataset component dispatches the events to the connected data sources. Each data source calls the NotifyDataLinks method to forward the event to each connected data link, and then the data source triggers its own OnDataChange or OnUpdateData event.
The TDataLink class is not technically an abstract class, but you'll seldom use it directly. When you need to create data-aware controls, you'll need to use one of its derived classes or derive a new one yourself. The most important class derived from TDataLink is the TFieldDataLink class, which is used by data-aware controls that relate to a single field of the dataset. Most data-aware controls fall into this category, and the TFieldDataLink class solves the most common problems of this type of component.
All the table- or record-oriented data-aware controls define specific subclasses of TDataLink, as we'll do later. The TFieldDataLink class has a list of events corresponding to the virtual methods of the base class it overrides. This makes the class simpler to customize, because you can use event handlers instead of having to inherit a new class from it. Here's an example of an overridden method, which fires the corresponding event, if available:
procedure TFieldDataLink.ActiveChanged; begin UpdateField; if Assigned(FOnActiveChange) then FOnActiveChange(Self); end;
The TFieldDataLink class also contains the Field and FieldName properties that let you connect the data-aware control to a specific field of the dataset. The link keeps a reference to the current visual component, using the Control property.