TTMSFNCDataBinding
To get started with the databinding component, drop a TTMSFNCDataBinder (further referred to as databinder) component on the form. The databinder component is capable of binding single value components, lists, tables and grids as well as non published properties such as generic TList & TObjectList (Integer or String based). It also automatically updates when a dataset change occurs.
The chapters below demonstrate what is possible based on a TClientDataSet connected to the biolife.xml file provided by Embarcadero, a TDataSource and a single instance of
TTMSFNCDataBinder.
Binding a single value
Binding a single value can be done by adding an item to the databinder component, specifying the component, the field name and the property name. It shows the value based on the active record. There are several ways that this can be done.
Programmatically
procedure TFormDataBinding.UpdateLinks;
var
it: TTMSFNCDataBinderItem;
begin
TMSFNCDataBinder1.BeginUpdate;
it := TMSFNCDataBinder1.Items.Add;
it.&Object := TMSFNCHTMLText1;
it.BindType := dbbtSingleValue;
it.DataSource := DataSource1;
it.FieldName := 'Common_Name';
it.PropertyName := 'Text';
TMSFNCDataBinder1.EndUpdate;
TMSFNCDataBinder1.Active := True;
end;
ConnectSingle.
procedure TFormDataBinding.UpdateLinks;
begin
TMSFNCDataBinder1.ConnectSingle(TMSFNCHTMLText1, DataSource1, 'Text', 'Common_Name');
TMSFNCDataBinder1.Active := True;
end;
Designtime
The databinder component also registered designtime support retrieving components, fieldnames and properties and makes this easily selectable at designtime via the object inspector. Add an item to the Items collection inside the TTMSFNCDataBinder component, select the item in the object inspector and select the values necessary to bind a single value to the component as demonstrated below.

Result:


Binding a list (TStringList)
Binding a list is similar to binding a single value but it shows all the records in the dataset.
procedure TFormDataBinding.UpdateLinks;
var
it: TTMSFNCDataBinderItem;
begin
TMSFNCDataBinder1.BeginUpdate;
it := TMSFNCDataBinder1.Items.Add;
it.&Object := ListBox1;
it.BindType := dbbtList;
it.DataSource := DataSource1;
it.FieldName := 'Common_Name';
it.PropertyName := 'Items';
TMSFNCDataBinder1.EndUpdate;
TMSFNCDataBinder1.Active := True;
end;
procedure TFormDataBinding.UpdateLinks;
begin
TMSFNCDataBinder1.ConnectList(ListBox1, DataSource1, 'Items', 'Common_Name');
TMSFNCDataBinder1.Active := True;
end;

Binding a list (TCollection)
Binding a list based on TCollection is similar to binding a list based on TStringList. When binding a TStringList based component it is sufficient to set the property that represents the list (Items in case of a TListBox). Some components have a collection to represent the items and when using the above, it will add items to the collection but not visualize the content, as typically there is a Caption or Text property inside the TCollectionItem that is used to display the values inside the list.
To work with a TCollection instead of a TStringList in the databinder, you need to use the SubPropertyNames & the SubFieldNames collection and this immediately allows you to bind more than one sub-property. The PropertyName remains “Items”, but for each collection item that is automatically added to the “Items” collection, the SubPropertyNames & SubFieldNames collection specifies which properties of that item are bound to which fields. For each item inside the SubPropertyNames there is an equivalent in the SubFieldNames and vice versa. Below is a sample
based on the TTMSFNCListBox component.
procedure TFormDataBinding.UpdateLinks;
var
it: TTMSFNCDataBinderItem;
begin
TMSFNCDataBinder1.BeginUpdate;
it := TMSFNCDataBinder1.Items.Add;
it.&Object := TMSFNCListBox1;
it.BindType := dbbtList;
it.DataSource := DataSource1;
it.PropertyName := 'Items';
it.SubPropertyNames.Add.Value := 'Text';
it.SubFieldNames.Add.Value := 'Common_Name';
TMSFNCDataBinder1.EndUpdate;
TMSFNCDataBinder1.Active := True;
end;
procedure TFormDataBinding.UpdateLinks;
begin
TMSFNCDataBinder1.ConnectList(TMSFNCListBox1, DataSource1, 'Items', ['Text'], ['Common_Name']);
TMSFNCDataBinder1.Active := True;
end;
procedure TFormDataBinding.FormCreate(Sender: TObject);
begin
TMSFNCListBox1.DefaultItem.BitmapWidth := 32;
TMSFNCListBox1.DefaultItem.BitmapHeight := 32;
TMSFNCListBox1.ItemsAppearance.HeightMode := lihmVariable;
TMSFNCDataBinder1.ConnectList(TMSFNCListBox1, DataSource1, 'Items', ['Text', 'Bitmap'], ['Common_Name', 'Graphic']);
TMSFNCDataBinder1.Active := True;
end;
Binding a column/list will retrieve all fields and all records and display them in a column/list structure. This means that the component you want to bind needs to have a separate column and a list collection.
procedure TFormDataBinding.FormCreate(Sender: TObject);
begin
TMSFNCDataBinder1.ConnectColumnList(TMSFNCTreeView1, DataSource1, 'Nodes', 'Columns', 'Text', 'Values.Text');
TMSFNCDataBinder1.Active := True;
end;

Binding a grid
Binding a grid is only possible when the component you are targeting implements the
ITMSFNCDataBinderGrid interface. You can either use the interface, or redefine the interface with the correct GUID.
ITMSFNCDataBinderBase = interface
['{778B63C9-34E3-4B65-A6B8-85E3EB1D17C3}']
procedure DataBeginUpdate;
procedure DataEndUpdate;
end;
ITMSFNCDataBinderGrid = interface(ITMSFNCDataBinderBase)
['{D23BDEAA-49B1-451A-9401-0D0D11A9957A}']
procedure SetDataColumnCount(AValue: Integer);
procedure SetDataRowCount(AValue: Integer);
procedure ClearData;
function GetDataRowCount: Integer;
procedure SetDataValue(AColumn, ARow: Integer; AValue: string);
procedure SetDataHeader(AColumn: Integer; AValue: string);
end;
Then after implementing the correct interfaces, you can use the following code to bind to a grid
procedure TFormDataBinding.FormCreate(Sender: TObject);
begin
TMSFNCDataBinder1.ConnectGrid(TMSFNCGrid1, DataSource1);
TMSFNCDataBinder1.Active := True;
end;

Binding a TList/TObjectList
Next to TStringList & TCollection there is also support for TList & TObjectList properties based on Integer & Strings. The sample below defines a TPersistent object with 2 published properties, bound to a data source.
TListObject = class(TPersistent)
private
FL: TList<Integer>;
FS: TList<string>;
public
constructor Create;
destructor Destroy; override;
published
property L: TList<Integer> read FL;
property S: TList<string> read FS;
end;
procedure TFormDataBinding.Bind;
var
o: TListObject;
begin
o := TListObject.Create;
try
TMSFNCDataBinder1.Items.Clear;
TMSFNCDataBinder1.ConnectList(o, DataSource1, 'L', [], ['Price']);
TMSFNCDataBinder1.ConnectList(o, DataSource1, 'S', [], ['Brand']);
o.Log;
ClientDataSet1.First;
ClientDataSet1.Edit;
ClientDataSet1.Fields[1].AsString := 'Hello World!';
ClientDataSet1.Post;
o.Log;
finally
o.Free;
end;
end;
Result
Debug Output:
{"$type":"TListObject","L":[699000,1268000,2096000,2000000,3881000,1659000,929000,9740500,690
000,2010000,2035825,1175000,4779500,3950000,1685000,1259000,7410000,4537000,12445000,9065
00,1053000],"S":["Alfa Romeo","MERCEDES","TVR","Wiesmann","Honda","Lexus","Mazda","Rolls
Royce","Audi","JAGUAR","MASERATI","LOTUS","FERRARI","BMW","PORSCHE","PEUGEOT","LAMBORGHINI"
,"DE TOMASO","MERCEDES","MG","Chrysler"]} Process DataBindingTest.exe (1612)
And the result after editing a value to “Hello World!”
Debug Output:
{"$type":"TListObject","L":[699000,1268000,2096000,2000000,3881000,1659000,929000,9740500,690
000,2010000,2035825,1175000,4779500,3950000,1685000,1259000,7410000,4537000,12445000,9065
00,1053000],"S":["Hello World","MERCEDES","TVR","Wiesmann","Honda","Lexus","Mazda","Rolls
Royce","Audi","JAGUAR","MASERATI","LOTUS","FERRARI","BMW","PORSCHE","PEUGEOT","LAMBORGHINI"
,"DE TOMASO","MERCEDES","MG","Chrysler"]} Process DataBindingTest.exe (14732)
Sub collections
In the binding column/list chapter, you can see the sub property that is being targeted for the TTMSFNCTreeView “Nodes” collection is “Values.Text”. There is ofcourse no property named this way, but when activating the database adapter, the “Nodes” collection is filled with items. Each item represents a node (TTMSFNCTreeViewNode), and each node has a property called “Values”. This represents the value for each column. When adding a TTMSFNCTreeViewNodeValue inside the “Values” collection, you can set a “Text” property that will then be displayed in the treeview. To make this work we have added support in the database adapter to go a level deeper when necessary. When the sub property under the main property is also a TCollection, it will add a value and then access the property afterwards and set the value of the field accordingly.
TMSFNCDataBinder1.ConnectList(TMSFNCTreeView1, DataSource1, 'Nodes', ['Values.Text', 'Values.Text', 'Values.CollapsedIcon'], ['Common_Name', 'Category', 'Graphic']);

HTML Template
For the single value and list bindings, there is support to add a HTML template instead of binding to a specific field name. The HTML template supports multiple fields as long as they follow a specific kind of format. The HTML itself is based on the mini HTML reference https://www.tmssoftware.com/site/minihtml.asp
The format for adding fields is: <#FIELDNAME>.
So when applying this to the single value binding for example we can add an item using the
TMSFNCDataBinder1.ConnectSingleHTMLTemplate(TMSFNCHTMLText1, DataSource1, 'Text', '<b>Name: <#COMMON_NAME></b><br/><#NOTES>');
procedure TFormDataBinding.UpdateLinks;
var
it: TTMSFNCDataBinderItem;
begin
TMSFNCDataBinder1.BeginUpdate;
it := TMSFNCDataBinder1.Items.Add;
it.&Object := TMSFNCHTMLText1;
it.BindType := dbbtSingleValue;
it.DataSource := DataSource1;
it.PropertyName := 'Text';
it.HTMLTemplate := '<b>Name: <#COMMON_NAME></b><br/><#NOTES>';
TMSFNCDataBinder1.EndUpdate;
TMSFNCDataBinder1.Active := True;
end;

Editor
The databinder component installs an editor that is available at designtime and at runtime. To start it at runtime, call
At designtime, you can right-click the editor and select“Edit…” to start the editor.

The editor allows you to edit, add and delete bindings. Click on Edit Mode to make changes to existing bindings. Click on the + sign at the top left to add a new binding and when in edit mode, select new components to start a new configuring a new binding. The comboboxes will list properties based on the bind component and the datasource. The datasource can be selected in the upper right corner next to the bind type.
Notifying the DataBinder of Changes
Overview
The TMS FNC DataBinder component provides a sophisticated notification system that allows bound controls and components to inform the databinder when their values have changed. This enables the databinder to automatically synchronize the updated values back to the underlying dataset, maintaining data consistency between the user interface and the data layer.
Notification Architecture
Notification Types
The databinder supports several types of notifications, defined by the TTMSFNCDataBinderNotificationType enumeration:
TTMSFNCDataBinderNotificationType = (
dbntUpdate, // General update notification
dbntEdit, // Edit mode notification
dbntPost, // Post changes notification
dbntValueChanged, // Value has changed notification
dbntSetActiveRecord // Active record selection notification
);
Notification Interfaces
ITMSFNCDataBinderNotification
Controls and components can implement this interface to participate in the notification system:
ITMSFNCDataBinderNotification = interface
['{3CEED28B-A125-4B26-B765-72785F2B0180}']
function GetObject: TObject;
procedure SetObject(const Value: TObject);
procedure Notify(AType: TTMSFNCDataBinderNotificationType);
property &Object: TObject read GetObject write SetObject;
end;
ITMSFNCDataBinderNotificationManager
The notification manager interface handles the distribution of notifications:
ITMSFNCDataBinderNotificationManager = interface
['{AFAFFAD9-AA33-4063-9BCB-6A17EC97D5C1}']
procedure Notify(AControl: TObject; AType: TTMSFNCDataBinderNotificationType);
end;
Notification Methods
Direct Notification Methods
The TTMSFNCDataBinderItem class provides several convenience methods for triggering specific types of notifications:
NotifyValueChanged
Call this method when the bound control's value has changed and needs to be written to the dataset.NotifyEdit
Triggers edit mode on the dataset, preparing it for value updates.NotifyPost
Posts pending changes to the dataset.NotifyUpdate
Forces a general update of the databinding relationship.NotifySetActiveRecord
Updates the active record position in the dataset based on the control's selection.Master Notification Method
All notification methods eventually call the central Notify method:
This method handles the actual notification processing based on the type:
case AType of
dbntSetActiveRecord:
begin
// Update dataset record position based on control selection
if Supports(&Object, ITMSFNCDataBinderSelection, bs) then
begin
r := bs.DataGetItemIndex + 1;
if r >= 1 then
FDataLink.DataSource.DataSet.RecNo := r;
end;
end;
dbntUpdate: UpdateDataLink(dlmUpdateData);
dbntEdit: DataSetEdit;
dbntValueChanged: WriteValueToField;
dbntPost: DataSetPost;
end;
Automatic Monitoring
Observer Pattern Implementation
The databinder can automatically monitor bound controls using the observer pattern, eliminating the need for manual notifications in many cases.
Control Value Monitor
For controls that support the IControlValueObserver interface:
TTMSFNCDataBinderControlValueMonitor = class
procedure StartMonitoring;
procedure StopMonitoring;
property Active: Boolean read FActive;
end;
Edit Link Monitor
For controls that support the IEditLinkObserver interface:
TTMSFNCDataBinderEditLinkMonitor = class
procedure StartMonitoring;
procedure StopMonitoring;
property Active: Boolean read FActive;
end;
Automatic Observer Setup
When a databinder item is created and configured, it can automatically set up observers for supported controls:
function GetControlValueMonitor: TTMSFNCDataBinderControlValueMonitor;
begin
if not Assigned(FControlValueMonitor) and
not FDataBinder.HasEditLinkMonitor(&Object) and
not FDataBinder.HasControlValueMonitor(&Object) then
begin
FControlValueMonitor := TTMSFNCDataBinderControlValueMonitor.Create(Self);
FControlValueMonitor.StartMonitoring;
end;
Result := FControlValueMonitor;
end;
Manual Notification Examples
Basic Value Change Notification
// When a control's value changes
procedure TMyControl.ValueChanged;
var
DataBinderItem: TTMSFNCDataBinderItem;
begin
// Find the databinder item for this control
DataBinderItem := MyDataBinder.ItemByObject[Self, 'Text'];
if Assigned(DataBinderItem) then
DataBinderItem.NotifyValueChanged;
end;
Edit and Post Sequence
// Complete edit sequence
procedure TMyForm.UpdateRecord;
var
DataBinderItem: TTMSFNCDataBinderItem;
begin
DataBinderItem := MyDataBinder.ItemByObject[MyEdit, 'Text'];
if Assigned(DataBinderItem) then
begin
DataBinderItem.NotifyEdit; // Put dataset in edit mode
DataBinderItem.NotifyValueChanged; // Write the value
DataBinderItem.NotifyPost; // Post the changes
end;
end;
Selection Change Notification
// When a list control's selection changes
procedure TMyListControl.SelectionChanged;
var
DataBinderItem: TTMSFNCDataBinderItem;
begin
DataBinderItem := MyDataBinder.ItemByObject[Self, 'Items'];
if Assigned(DataBinderItem) then
DataBinderItem.NotifySetActiveRecord;
end;
Global Notification
DataBinder-Level Notifications
The main databinder component provides methods to notify all bound items:
// Notify all bound controls
MyDataBinder.NotifyValueChanged; // All items write their values
MyDataBinder.NotifyEdit; // All items enter edit mode
MyDataBinder.NotifyPost; // All items post their changes
MyDataBinder.NotifyUpdate; // All items refresh from dataset
MyDataBinder.NotifySetActiveRecord; // All items update active record
WriteValueToField Implementation
The core method that actually writes the control value to the dataset:
procedure WriteValueToField;
begin
if CheckDataSet and (DataSetIsEditing or DataSetIsInserting) then
begin
FDirty := True;
UpdateDataLink(dlmUpdateData);
end;
end;
This method: 1. Checks if the dataset is active and in edit mode 2. Marks the item as dirty 3. Triggers a data link update to write the value
Best Practices
1. Use Automatic Monitoring When Possible
Let the databinder automatically monitor standard controls rather than implementing manual notifications.
2. Implement Notification Interfaces for Custom Controls
For custom controls, implement ITMSFNCDataBinderNotification to participate in the notification system.
3. Batch Notifications
When updating multiple controls, use the global notification methods to ensure consistency.
4. Handle Edit Mode Properly
Always ensure the dataset is in edit mode before attempting to write values:
if DataBinderItem.DataSetCanModify then
begin
DataBinderItem.NotifyEdit;
DataBinderItem.NotifyValueChanged;
end;
5. Error Handling
Wrap notification calls in try-except blocks for robust error handling:
try
DataBinderItem.NotifyValueChanged;
except
on E: Exception do
ShowMessage('Error updating data: ' + E.Message);
end;
Note
All notification methods eventually call the central Notify method which handles the actual notification processing based on the type.
Tip
Use automatic monitoring when possible - let the databinder automatically monitor standard controls rather than implementing manual notifications.
Important
Always ensure the dataset is in edit mode before attempting to write values to prevent data integrity issues.
Conclusion
The TMS FNC DataBinder notification system provides flexible and powerful mechanisms for keeping bound controls synchronized with dataset values. By understanding and properly utilizing these notification methods, developers can create responsive data-aware applications that automatically maintain data consistency between the user interface and underlying data sources.