Automate UI‑Data Sync in Delphi with LiveBindings
LiveBindings eliminates manual event wiring by connecting controls to datasets through a TBindingsList. This guide shows a minimal VCL setup, the code‑level binding pattern, and where the approach breaks down.
13 Apr 2026, 20:58 UTC

The problem: manual data‑binding boilerplate
In a typical VCL or FMX application you write OnChange, OnExit, or AfterScroll handlers to push values between edits, grids, and a TDataSet. That code is repetitive, error‑prone, and hard to maintain when the UI grows.
Useful takeaway
LiveBindings replaces those handlers with a declarative binding graph. A TBindingsList owns TBinding objects that connect a TBindingSource (wrapping a dataset field) to a visual control. The framework propagates changes in both directions, handles formatting, and validates input without you writing a single event.
Core mechanism
Components you’ll use
- TClientDataSet – in‑memory dataset (or any
TDataSetdescendant). - TBindingsList – container that manages the lifetime of all bindings on a form.
- TBindingSource – adapter that exposes a dataset field as a bindable source.
- TDBText,
TEdit,TComboBox, etc. – target controls that implementIBindableComponent.
Designer‑driven setup (fastest for prototypes)
- Create a new Delphi VCL project (RAD Studio 11 Alexandria or later).
- Drop a
TClientDataSet(cdsPeople), add a fieldName(string), and callCreateDataSet. - Place a
TBindingsList(BindingsList1) on the form. - Add a
TDBText(DBTextName) where you want the name displayed. - Open the LiveBindings Designer (View → LiveBindings Designer), drag from
cdsPeople.FieldByName('Name')toDBTextName.Caption. The designer creates aTLinkControlToFieldbinding automatically. - Run the application. Edit the dataset programmatically (e.g.,
cdsPeople.Edit; cdsPeople.FieldByName('Name').AsString := 'Alice'; cdsPeople.Post;) and theTDBTextupdates instantly.
Code‑level binding (explicit, version‑controlled)
When you need the binding in a non‑visual module or want to avoid the designer, create it in FormCreate:
uses
System.Bindings.Helper, Data.Bind.Components, Data.Bind.DBScope;
procedure TForm1.FormCreate(Sender: TObject);
var
Src: TBindingSource;
Bind: TBinding;
begin
// Ensure the dataset is active
cdsPeople.CreateDataSet;
cdsPeople.Open;
// Wrap the field in a binding source
Src := TBindingSource.Create(Self);
Src.DataSet := cdsPeople;
Src.DataField := 'Name';
// Create a two‑way link between the source and the DBText.Caption property
Bind := TBindingsList1.Bindings.Add(TBinding.Create(Src, DBTextName, 'Caption'));
// Optional: add formatting/validation via Bind.Expression
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// Explicit cleanup prevents memory leaks
BindingsList1.Free;
// TBindingSource owned by the form is freed automatically
end;
Where to run: In the form’s unit, with System.Bindings.Helper, Data.Bind.Components, Data.Bind.DBScope in the uses clause. Requires no elevated permissions; runs in the main UI thread.
Expected check: After cdsPeople.FieldByName('Name').AsString := 'Bob'; the DBTextName.Caption shows "Bob" without any event code.
Risk: If you forget to free BindingsList1 (or the form’s TBindingSource instances) you leak the binding graph. Always free in FormDestroy or use an interface‑based owner.
Limits and when to avoid LiveBindings
Performance with large data sets
LiveBindings evaluates expressions on every change notification. With thousands of rows or complex calculated fields the UI thread can stall. For high‑volume grids or real‑time feeds, bind only the visible row or switch to manual OnGetText/OnSetText handling.
Memory management
Each TBinding and TBindingSource holds references to both the dataset and the control. Circular references are broken only when the TBindingsList is destroyed. In long‑lived forms (e.g., a main window that stays open) this is fine; in dynamically created/destroyed frames you must call BindingsList.Free explicitly.
Complex expressions and validation
The designer supports simple property‑to‑field links. For multi‑field calculations, conditional formatting, or cross‑control validation you must write custom TBindingExpression subclasses – which defeats the low‑code benefit. In those cases a dedicated presenter/view‑model layer is cleaner.
Common mistakes
- Binding to a closed dataset: The source field must be active (
DataSet.Active := True) before the binding is added. - Using the wrong property name:
TDBTextbinds toCaption,TEdittoText. Check the control’sIBindableComponentimplementation. - Leaving orphan bindings in frames: When a frame is freed, its
TBindingsListmust be freed first; otherwise the parent form’s binding list retains dangling references.
Practical verification steps
- Build and run the VCL project described above.
- In the debugger, pause after
cdsPeople.Postand inspectDBTextName.Caption– it should match the dataset value. - Change the dataset field again via code (no UI interaction) and confirm the control updates.
- Close the form; verify no memory‑leak report appears (enable
ReportMemoryLeaksOnShutdown := Truein the project source).
Version assumptions
LiveBindings is built‑in from RAD Studio 11 (Delphi 11 Alexandria) onward. Versions 10.4 and earlier required the separate LiveBindings package installation. The code example compiles under Delphi 11, 12, and 13 with the standard VCL library.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.