Decoupling UI and Data in FMX with LiveBindings: A Practical Guide
LiveBindings lets FMX developers decouple UI from data models, cutting boilerplate and improving maintainability. This guide walks through building a CRUD grid, performance tips, and when to avoid LiveBindings.
30 Jul 2025, 02:42 UTC

Problem: Manual Wiring of UI and Data
When building a cross‑platform FireMonkey (FMX) app, developers often find themselves writing repetitive code to keep the UI in sync with the underlying data. A typical pattern is:
procedure TForm1.Edit1Change(Sender: TObject);
begin
DataObject.Name := Edit1.Text;
end;
procedure TForm1.DataObjectChanged;
begin
Edit1.Text := DataObject.Name;
end;
This two‑way wiring is error‑prone, hard to maintain, and duplicates logic across many controls. LiveBindings in RAD Studio offers a declarative alternative that eliminates most of this boilerplate.
Thesis: Use LiveBindings to Decouple UI from Data Models
LiveBindings lets you describe relationships between UI components and data objects once, then let the framework handle synchronization automatically. The result is:
- Fewer lines of code
- Clear separation of concerns
- Easier debugging via the visual
TBindNavigator - Consistent behaviour on Windows, Android, iOS, macOS, and Linux
1. Core Components of LiveBindings
Understanding the building blocks is essential before you start wiring.
- TBindSourceDB – Wraps a data source (e.g.,
TDataSetor a custom object) and exposes its properties to the binding system. - TBindList – Handles collections, such as a
TListVieworTStringGrid. - TBindNavigator – A visual designer that lets you drag‑and‑drop bindings and see the data flow graph.
- TBindExpression – Allows you to write simple Pascal expressions that compute values on the fly.
2. Building a CRUD Grid with LiveBindings
Below is a step‑by‑step example that demonstrates a fully functional CRUD grid on Windows and Android. The data model is a plain TFoo object stored in a TList.
- Create the Data Model
type TFoo = class private FName: string; FValue: Integer; public property Name: string read FName write FName; property Value: Integer read FValue write FValue; end; - Instantiate the List and BindSource
var FooList: TList<TFoo>; BindSourceFoo: TBindSourceList<TFoo>; FooList := TList<TFoo>.Create; BindSourceFoo := TBindSourceList<TFoo>.Create(Self); BindSourceFoo.List := FooList;Run-time creation is shown here; you can drop a
TBindSourceListcomponent onto the form instead. - Design the UI
TListView– Set itsItemAppearancetoDefault.TButton– AddbtnAdd,btnDelete, andbtnSave.
- Wire the Bindings with
TBindNavigatorDrop a
TBindNavigatoronto the form. In its designer:- Source:
BindSourceFoo. - Target:
ListView1. - Bind the
Namefield to theTextproperty of the list item’sLabel, andValueto aNumberfield. - Enable
AutoCreateso new items appear automatically.
Result: Adding a
TFootoFooListinstantly updates the ListView. - Source:
- Implement CRUD Buttons
procedure TForm1.btnAddClick(Sender: TObject); var NewFoo: TFoo; begin NewFoo := TFoo.Create; NewFoo.Name := 'New Item'; NewFoo.Value := 0; FooList.Add(NewFoo); // No need to refresh the ListView – LiveBindings handles it. end; procedure TForm1.btnDeleteClick(Sender: TObject); var Selected: TFoo; begin Selected := BindSourceFoo.Current; if Assigned(Selected) then begin FooList.Remove(Selected); Selected.Free; end; end; procedure TForm1.btnSaveClick(Sender: TObject); begin // Persist FooList to database or file here. end;Notice the absence of any manual UI updates; the bindings keep everything in sync.
3. Performance & Debugging Tips
- Large Datasets – Binding every cell in a
TStringGridcan be expensive. UseTBindListwithVirtualmode to render only visible rows. - Expression Complexity –
TBindExpressionis great for simple calculations but can become hard to debug. Keep expressions short and test them in isolation. - Memory Management – Every
TBindSourceholds references to its data. Ensure you free the source when the form is destroyed:BindSourceFoo.Free; - CPU Profiling – Use RAD Studio’s CPU Profiler on Android to spot binding‑related bottlenecks. Look for spikes in
LiveBindingsmodules.
4. When LiveBindings Might Not Be the Right Choice
LiveBindings shines for CRUD‑heavy, data‑driven UIs, but there are scenarios where you might prefer traditional event handling:
- Performance‑critical animations that require fine‑grained control over render loops.
- Complex, non‑linear data transformations that exceed what
TBindExpressioncan express. - Legacy codebases that already use extensive manual binding logic; migrating to LiveBindings may not justify the effort.
Actionable Checklist
- Identify data‑heavy screens and assess if they involve CRUD operations.
- Replace manual property setters/getters with a
TBindSourceListorTBindSourceDB. - Use
TBindNavigatorto create bindings visually; verify the data flow graph. - Profile the app on target platforms; if you notice a >10% CPU increase, consider virtual lists or reduce binding granularity.
- Document any custom
TBindExpressionlogic in comments for future maintainers.
By following this workflow, you’ll reduce boilerplate, improve maintainability, and harness RAD Studio’s LiveBindings to its full potential.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.