A perhaps not so well known fact about LiveBindings is that they can be used in VCL as well as FireMonkey applications. The traditional VCL data-aware controls are still available though and for reasons that will quickly become apparent, I wouldn’t advise ripping out your VCL TDBEdits just yet.
We’re going to build the same application as we did in part 1 but for VCL. You might be tempted to skip over this tutorial but I’d advise against it. Due to a lack of features in the LiveBindings design-time support for VCL there are a lot more manual steps we have to do and these steps are also very applicable for FireMonkey. Also what you’ll learn in this tutorial will help you when we move onto more complex and interesting LiveBinding uses.
Position the controls
First we create a new VCL application by selecting
- File
- New
- VCL Forms Application
Now we need a database for our application to access. Drop a TClientDataSet (or any other TDataSet descendent) and a TDataSource on the form just as you would in any other VCL application.
Connect the TDataSource to the TClientDataSet by it’s DataSet property, exactly as you normally do.
If you used a TClientDataSet you’ll need to specify an XML data file for it to load. I’m using the biolife.xml file from the Delphi XE2 samples directory.
Next drop onto the form one of each of these standard controls
- TLabel
- TEdit
- TMemo
And now drop a TStringGrid onto the form.
Your form should now resemble this.
Setup the Binding Engine
Now we need to start binding these standard controls to the database fields.
Drop a TBindingsList anywhere onto your form.
Follow it with a TBindScopeDB, also anywhere on your form.
Now we link the binding engine to the database engine by the DataSource property of the TBindScopeDB.
Bind the TLabel
It’s at this point that the steps required for VCL LiveBindings differ significantly from the optimal steps for FireMonkey LiveBindings. All of these steps will work in FireMonkey too though, they’re just not the quickest and easiest way to do it.
With the TLabel selected, in the Object Inspector select
- LiveBindings
- Dropdown arrow
- New LiveBinding
To jog your memory here’s the same object inspector property dropdown list for the FireMonkey version of this application. For the FireMonkey version we selected the “Link to DB Field” option however the “New LiveBinding” option is also available.
The “New LiveBinding” dialog lists the types of Bind Components available to you. The “Links” branch represent classes to designed expressly to link UI controls to database fields.
We want to use the simplest type of link, a “TBindLink” which links a single valued control like a TLabel or TEdit with a single database field.
Double click the TBindingsList component on your form to display the Bindings List dialog.
This is primary reason you have a TBindingsList component on your form, you really don’t do much else with it in most cases.
The Bindings List dialog should contain a single bind component, “BindLinkLabel11” as shown below.
Select the BindLinkLabel11 bind component from the list and check that the Object Inspector now shows BindLinkLabel11 and its properties.
In the Object Inspector set the SourceComponent to the TBindScopeDB component on your form.
If you look in the dropdown list you’ll also see the TLabel component we’re binding to in that list. It’s important you don’t select that TLabel. For SourceComponent think data source and while the TDataSource is also in that list, you need to connect to the TBindScopeDB which is in turn connected to the TDataSource.
Set the SourceMemberName to the database field you wish to display in the TLabel.
In this instance “Source” is the source of the data, “Member” is a field of that data source and “Name” is the name of that field.
The list entry for the bind component should almost read like a sentence expressing how the binding should behave.
Double click the bind component in the list, in this case the BindLinkLabel11.
You should see the Binding Expression Editor dialog as shown below.
Binding Expressions are instructions for the LiveBindings engine on exactly how to bind, in this instance, a database field to a UI control.
For a TBindLink bind component there are 3 types of expressions, Format, Parse and Clear expressions. These represent instructions to the LiveBindings engine on formatting data to display to the user, parsing the data entered by the user and clearing the data to an empty or default value.
Select the “Format” collection of expressions.
Now click the “New Expression” button above it (look for the yellow page icon).
A new expression will appear in the list named “Format[0]”.
Note its “Operation” reads “Assign to control”.
The “Control expression for Label1” is the expression that the LiveBindings engine will use to assign a value to the TLabel.
Enter “Caption” as this value for this expression. By doing this you are directly referring to the TLabel.Caption property.
The “Source expression for BindScopeDB1, CommonName:” is the expression that the LiveBindings engine will use to format the data it reads from the database field.
Enter DisplayText as the value for this expression. By doing this you are directly referring to the TField.DisplayText property. You could also use AsString, Value or Text, all of which are properties of TField and achieve a similar or identical result.
You might have noticed these tick and cross buttons to the right of the expressions. If you click the tick button the expression value you entered will immediately be reflected in the expression list above.
Clicking the tick button is optional though as closing the dialog or switching to another expression has the same effect.
Your completed expression should appear like this.
Close the Expression Editor dialog and then close the Bindings List dialog beneath it to return to the form.
Bind the TEdit
Once again the process for binding the TEdit starts in a similar way. Select the TEdit and then in the Object Inspector click
- LiveBindings
- Dropdown arrow
- New LiveBinding
Again we select TBindLink as it is the most appropriate bind component for linking a single database field with a single valued UI control.
Double click the TBindingsList component on your form to display the Bindings List dialog.
You’ll now have 2 bind components listed, one for the TLabel and one for the TEdit.
Select the BindLinkEdit11 bind component from the list and ensure it is shown in the Object Inspector.
Set the BindLinkEdit11.SourceComponent property in the Object Inspector remembering that the “source” is synonymous with the “data source” and that the TBindScopeDB is link between the LiveBindings engine and the TDataSource.
The SourceMemberName property is the database field name you wish to bind to.
The BindLinkEdit11 in the bind components list should now almost read as a sentence expressing how the control will be bound to the field.
Double click the BindLinkEdit11 bind component in the list to display the Expression Editor dialog.
With the “Format” collection selected press the “New Expression” button (leftmost button, with the yellow document icon).
A new expression will appear in the list, note its operation is “Assign to control”.
The “Control expression” refers to the property of the TEdit we wish to bind to.
Enter the word “Text” which will directly refer to the TEdit.Text property.
It is possible to enter any TEdit property here although it really only makes sense to use the Text property.
The “Source expression” refers to the property of TField that we wish to use as the source for the binding.
You can use any TField property, in this case I’ve chosen TField.AsString which for an Edit control is more appropriate than TField.DisplayText.
Click on the “Parse” collection.
Click the “New Expression” button again to create a new expression named Parse[0].
Note its operation is “Assign to source” rather than “Assign to control”. A Parse expression describes how the input from the user should be parsed and assigned to the field or “data source”.
The “Control expression” refers to the TEdit property we want the binding to read when saving its value to the database.
Enter “Text” to tell it to use the TEdit.Text property.
For the “Source expression” enter the TField property you wish to be set by the binding when data is saved to the field.
The most appropriate TField property is “Value” although you could also use TField.AsString.
Note that despite the fact that we’re now sending data in the opposite direction from the “Format” expression, the “source” still refers to the database field, rather than the UI control.
The use of the term “source” can be a little confusing because of this as right now our “source” is actually the destination. It’s best not to think in terms of source and destination but instead keep in mind the data “source” and the UI “control”.
Bind the TMemo
Close both dialogs to return to the form then select the TMemo and in the Object Inspector click
- LiveBindings
- Dropdown arrow
- New LiveBinding
Once more choose a TBindLink to link a single valued control to a database field.
Double click the TBindingsList component on your form to display the Bindings List dialog.
Select the BindLinkMemo11 bind component from the list.
With the BindLinkMemo11 properties displayed in the Object Inspector set the SourceComponent to your form’s TBindScopeDB component which in turn is linked to the TDataSource.
As we’re binding to a TMemo the SourceMemberName will refer to BLOB field from the “data source”.
In the biolife.xml dataset the “Notes” field is a BLOB text field.
The BindLinkMemo11 should now almost read as a set of instructions to the LiveBindings engine as below.
Double click the BindLinkMemo11 bind component in the list to display the Expression Editor dialog.
Select the “Format” collection and click the “New Expression” button above it (look for the yellow document icon).
A new expression named Format[0] will be added to the list. This expression instructs the LiveBindings engine on how to display the data to the user.
The “Control expression for Memo1” refers to the property of TMemo that needs to be updated with the field value from the database.
As TMemo uses a TStrings object to store its data internally we need to reference that internal TStrings object via the TMemo.Lines property, then reference the TStrings.Text property for a single property that can be set.
Enter “Lines.Text” which directly refers to the TMemo.Lines.Text property.
The “Source expression” as usual refers to the field from the “data source”/database.
Enter “AsString” to use the TField.AsString property.
If you were to use the TField.DisplayText property you’ll see something familiar but not quite what you’re after. For a BLOB text field TField.DisplayText returns “(MEMO)” rather than the actual text. This is what you’re used to seeing for BLOB fields in the TDBGrid.
Click on the “Parse” collection and then the “New Expression” button above it.
A new expression named “Parse[0]” will be added to the list.
Note its operation reads “Assign to source” rather than “Assign to control”. This is the expression that instructs the LiveBindings engine on how to read the data from the user and save it to the database.
The “Control expression” refers to the property of the TMemo we can interrogate to obtain the data entered by the user.
Enter “Lines.Text” to instruct the LiveBindings engine to read the TMemo.Lines.Text property when parsing the user input.
The “Source expression” refers to the database field where the data is to be saved (despite being called the “source”).
Use the “Value” property to store the user input in the TField.Value property.
The TField.AsText property would work here equally as well.
Open the DataSet and run the application
At run-time in the FormCreate event open your dataset.
Run the finished application.
Finished application?
Err… excuse me…
What about the Grid?
This is where the LiveBindings design-time VCL support really doesn’t measure up. While it’s a little annoying to have to create the LiveBindings manually for TEdit, TLabel and TMemo controls for a TStringGrid the annoyance factor goes off the charts.
For LiveBindings to operate on a TStringGrid you have to create multiple bindings for columns, rows, cells, positions… It’s a task that’s reduced to just a few clicks in FireMonkey but currently for VCL it’s just hard work.
If I’m brave enough I’ll devote a future article to how to create these manual bindings for a TStringGrid. It’s something you really don’t ever want to have to do yourself though so hopefully the VCL design-time support is improved soon.
Thanks for the article. Makes me think TDataSource and TDBGrid aren’t that bad after all!
Don’t write off LiveBindings just yet. While they’re a little clunky in the VCL, there’s plenty more I’ll be exploring in this series and I expect that their usability in the VCL will improve in the near future.
Wow. I thought I was the only one who thought LiveBindings with a TStringGrid is convoluted and nearly useless with a VCL stringgrid. Populating a stringgrid using LiveBindings in FireMonkey is very slow with a moderate size clientdatabase compared to similar code in a VCL DBGrid. Perhaps because stringgrid does not have BeginUpdate or EndUpdate to inhibit redrawing the screen. With an 584 kb *.cds clientdatabase with 26 columns and 5000 records, the FM stringgrid takes about six to ten seconds to “load” to a stringgrid. A VCL DBGrid loads “instantaneously” with the identical clientdataset. I expect this dataset will also load at snail’s pace with a VCL LiveBinding to a stringgrid.
Thanks for showing how to deal with LiveBindings for several VCL controls. Your upcoming tutorial will be appreciated. I want to compare the filling of the DBGrid with the VCL LiveBbindings with my dataset.
Embarcadero’s LiveBindings database examples with clientdata set use very small datasets and are useless to convert for use with my own data without the step by step instructions you hopefully will provide to set-up the controls. The Embarcadero VCL LiveBindings examples load and populate the grid. The process ‘looks’ fast but I expect probably would be slow with a moderate database like I am have. Perhaps I am missing a ‘trick’ to speed up loading a VCL or FM grid using LiveBindings?
I am very much looking forward to your next tutorial. Thank you.
— SteveJG
I’ll be covering grids in several more parts to this series. Some showing how you hook them up, others discussing the issues you’ve mentioned.
Did Microsoft patent binding things the simple way with dotNet?
I’d rather write a big pile of
Edit1.Text := DataSet.FieldByname(‘Field1’).AsString;
And the reverse saving logic. At least it is clear, easy to read and maintainable. This, this is just… If I was honest and used the words that come to mind, I would get a second post in a week nuked.
Let’s go with ugly, tedious, over complicated, fragile and very easily broken – all things to be avoided when possible.
Take a look at Part 1 of this series to see how LiveBindings for VCL will likely look in the near future. In FireMonkey LiveBindings are much simpler to use but you still have access to their full power and flexibility (which I haven’t yet explored in this series).
TBH I don’t get the point of LiveBindings either, “manual” code-based binding is simple, straightforward, foolproof, in case of bugs you get compiler errors, you can place the code anywhere (not in the form), they’re simple to debug, and give a nice simple overview of what is bound to what.
LiveBindings on the other hand, even when they’re supported by the IDE, are convoluted to setup and very fragile as C J said.
I would also add that they’re obfuscated from casual review, mistakes are very hard to diagnose and tracing with the debugger is insanely confusing.