Tutorial: Creating Collection Lists Using LiveBindings
Go Up to Database and LiveBindings Tutorials
This tutorial demonstrates how to construct the application used in the ListCollections sample project.
Note: You can find the ListCollections sample project at:
Start | Programs | Embarcadero RAD Studio Athens | Samples and then navigate to Object Pascal\FireMonkey Desktop\ListCollections .
This sample is described in FMX.ListCollections Sample.
Contents
Step 1: Creating the Project
- Create a new project: File > New > Multi-Device Application - Delphi.
In the wizard, choose Blank Application. - Select the form, and change its Caption property in the Object Inspector to "List Collections Demo".
- Add a TLabel component to the form, and change its Text property in the Object Inspector to "Collection: ".
- In the Tool Palette, locate a ComboBox component and drop it onto the form.
-
In the Form Designer, right-click the ComboBox1 component and select Add Item > TListBoxItem.
-
Add four TLabel components to the form, and change the Text property for the respective components to:
"Control Component:", "Control Expression:", "Source Component:", "Source Expression:"
Also change the Name property respectively to:
"LabelControlComponent", "LabelControlExpression", "LabelSourceComponent" -
For each of of the labels ("LabelControlComponent", "LabelControlExpression", "LabelSourceComponent"), add a TEdit component, and change the Name property respectively to:
"EditControlComponent", "EditControlExpression", "EditSourceComponent"
Also for each TEdit set the Enabled property toFalse
. - Add a TEdit component to the form, and change the Name property to "EditSourceExpression".
-
Add two TButton components to the form, and change the Text property to "Fill" and "Clear" respectively.
Also change the Name property to "ButtonEvaluate" and "ButtonClear" respectively. -
Add three TCheckBox components to the form, and change the Text property respectively to:
"Auto Active", "Active", "Auto Fill"
Also change the Name property respectively to:
"CheckBoxAutoActive", "CheckBoxActive", "CheckBoxAutoFill"
- In the Tool Palette, locate a TListBox component and drop it onto the form.
- Add a TBindingList component to the form.
- On the form, right-click the BindingList1 component and select Binding Components...
-
In the Bindings List Editor, select New Binding (Ins).
- In the New LiveBinding dialog box, select Lists > TBindList.
-
In the Object Inspector, set the Control Component property to
ListBox1
.
Step 2:Implementation
- The SampleCollections.pas unit implements the additional supported collections of elements that will be exported to the List Box by means of LiveBindings. The sample used a class Factory Design Pattern to dynamically build several different types of collections:
- A dictionary
- A list of objects
- A list of generics
- A list of strings
- The ListCollections product sample is not appropriate for beginners (advanced knowledge is required; to read the code, you should know RTTI, and advanced language elements such as anonymous methods and Design Patterns).
Add the SampleCollections.pas unit to the project.
In the private section of TForm1 class, add these variables:
Delphi:
FChecking: Boolean;
FDataObjects: TDictionary<TCollectionFactory, TObject>;
FFactory: TCollectionFactory;
FChanging: Boolean;
Add to the unit variable:
Delphi:
var
BindScope1: TBindScope;
1. Add an OnCreate Form Event Handler
- 1. In the Structure View, select the Form1 component.
- 2. In the Object Inspector, open the Events tab, and then double-click OnCreate.
- 3. In the Code Editor, add the following code:
Delphi:
procedure TForm1.FormCreate(Sender: TObject);
var
LFactory: TCollectionFactory;
LListItem: TListBoxItem;
begin
BindScope1 := TBindScope.Create(Self);
BindList1.SourceComponent := BindScope1;
FDataObjects := TObjectDictionary<TCollectionFactory, TObject>.Create([doOwnsValues]);
// List test data in combobox
for LFactory in GetCollectionFactories do
begin
LListItem := TListBoxItem.Create(ComboBox1);
ComboBox1.AddObject(LListItem);
LListItem.Text := LFactory.DisplayName;
LListItem.Data := LFactory;
end;
Application.OnIdle := OnIdle;
UpdateDisplayFields;
end;
In the public section of TForm1 class, add these procedures:
Delphi:
procedure OnIdle(Sender: TObject; var Done: Boolean);;
procedure UpdateDisplayFields;
Implementation for the procedures above:
Delphi:
procedure TForm1.OnIdle(Sender: TObject; var Done: Boolean);
begin
FChecking := True;
try
CheckBoxActive.IsChecked := BindList1.Active;
CheckBoxAutoFill.IsChecked := BindList1.AutoFill;
CheckBoxAutoActivate.IsChecked := BindList1.AutoActivate;
finally
FChecking := False;
end;
end;
// Display information about binding
procedure TForm1.UpdateDisplayFields;
var
LSourceExpression: string;
LControlExpression: string;
LSourceComponent: string;
LControlComponent: string;
begin
if BindList1.FormatExpressions.Count > 0 then
begin
LSourceExpression := BindList1.FormatExpressions[0].SourceExpression;
LControlExpression := BindList1.FormatExpressions[0].ControlExpression;
end;
if BindList1.ControlComponent <> nil then
LControlComponent := BindList1.ControlComponent.ClassName;
if BindList1.SourceComponent <> nil then
begin
LSourceComponent := BindList1.SourceComponent.ClassName;
if BindList1.SourceComponent is TBindScope then
with TBindScope(BindList1.SourceComponent) do
if DataObject <> nil then
LSourceComponent := LSourceComponent + ' (' +
DataObject.ClassName + ')'
else if Component <> nil then
LSourceComponent := LSourceComponent + ' (' +
Component.ClassName + ')';
end;
EditSourceExpression.Text := LSourceExpression;
EditControlExpression.Text := LControlExpression;
EditControlComponent.Text := LControlComponent;
EditSourceComponent.Text := LSourceComponent;
end;
2. Add an OnChange ComboBox Event Handler
- 1. Select from Structure ComboBox1 component.
- 2. In the Object Inspector, open the Events tab, and then double-click OnChange.
- 3. In the Code Editor, add the following code:
Delphi:
procedure TForm1.ComboBox1Change(Sender: TObject);
var
LDataObject: TObject;
begin
FChanging := True;
try
if ComboBox1.ItemIndex <> -1 then
begin
FFactory := ComboBox1.ListBox.Selected.Data as TCollectionFactory;
end
else
begin
FFactory := nil;
end;
if FFactory <> nil then
begin
if BindList1.FormatExpressions.Count = 0 then
BindList1.FormatExpressions.Add;
BindList1.FormatExpressions[0].SourceExpression := FFactory.GetExpression;
BindList1.FormatExpressions[0].ControlExpression := 'Text';
LDataObject := FFactory.CreateCollection;
FDataObjects.AddOrSetValue(FFactory, LDataObject); // Track objects in order to free when not in use
// Set DataObject last because this can trigger activation and auto fill
BindScope1.DataObject := LDataObject;
end
else
BindScope1.DataObject := nil;
finally
FChanging := False;
UpdateDisplayFields;
end;
end;
3. Add OnClick Button Event Handler
- 1. In the Structure pane, select the ButtonEvaluate component.
- 2. In the Object Inspector, open the Events tab, and then double-click OnClick.
- 3. In the Code Editor, add the following code:
Delphi:
procedure TForm1.ButtonEvaluateClick(Sender: TObject);
begin
BindList1Activating(Self); // Update expression
BindList1.FillList;
end;
- 4. Repeat the steps above for ButtonClear, adding the following code in the Code Editor:
Delphi:
procedure TForm1.ButtonClearClick(Sender: TObject);
begin
BindList1.ClearList;
end;
4. Add an OnChange CheckBox Event Handler
- 1. Select the CheckBoxAutoActive component from Structure.
- 2. In the Object Inspector, open the Events tab, and then double-click OnChange.
- 3. In the Code Editor, add the following code:
Delphi:
procedure TForm1.CheckBoxAutoActivateChange(Sender: TObject);
begin
if not FChecking then
BindList1.AutoActivate := CheckBoxAutoActivate.IsChecked;
end;
- 4. Repeat the steps above for CheckBoxActive, and CheckBoxAutoFill, adding the following code in the Code Editor:
Delphi:
procedure TForm1.CheckBoxActiveChange(Sender: TObject);
begin
if not FChecking then
BindList1.Active := CheckBoxActive.IsChecked;
end;
Delphi:
procedure TForm1.CheckBoxAutoFillChange(Sender: TObject);
begin
if not FChecking then
BindList1.AutoFill := CheckBoxAutoFill.IsChecked;
end;
5. Add OnActivating and OnEvalError BindList Event Handlers
- 1. Select the BindList1 component from Structure.
- 2. In the Object Inspector, open the Events tab, and then double-click OnActivating.
- 3. In the Code Editor, add the following code:
Delphi:
procedure TForm1.BindList1Activating(Sender: TObject);
begin
if not FChanging then
if BindList1.FormatExpressions.Count > 0 then
BindList1.FormatExpressions[0].SourceExpression := EditSourceExpression.Text;
end;
- 4. In the Object Inspector, open the Events tab, and then double-click OnEvalError.
- 5. In the Code Editor, add the following code:
Delphi:
procedure TForm1.BindList1EvalError(Sender: TObject; AException: Exception);
begin
// Generate a new exception with more information
raise TBindCompException.CreateFmt(
'Evaluation Exception'#13#10 +
'Component Name: %s'#13#10 +
'Exception Class: %s'#13#10 +
'Exception Message: %s',
[TComponent(Sender).Name, AException.ClassName, AException.Message]);
end;
The Results
Press F9 or choose Run > Run.
Classes
List Collections Demo represents the main window of the sample. It contains the following components:
- Two TButton objects
- Four TEdit objects
- Five TLabel objects
- Three TCheckBox objects
- A TComboBox
- A TListBox
- A TBindingsList
- A TBindScope
- A TBindList
Uses
- FMX.StdCtrls.TButton
- FMX.Edit.TEdit
- FMX.StdCtrls.TLabel
- FMX.StdCtrls.TCheckBox
- FMX.ListBox.TComboBox
- FMX.ListBox.TListBox
- Data.Bind.Components.TBindingsList
- Data.Bind.Components.TBindScope
- Data.Bind.Components.TBindList