Delphi Binding Expressions, Properties and Components
May 28, 2021 by Marco Cantu
Continuing last week blog post on binding expressions, let's see how components can participate, but creating expressions that refer to properties.
Last week I introduced Delphi RTL expression engine in the blog post at Для просмотра ссылки Войдиили Зарегистрируйся. Now let's make an additional step. I want to explain how components and their properties can be part of these expressions. In this case we don't simply evaluate an expression, but want to associate two separate expressions in a "binding".
With this configuration code, if you call BindingExpression1.Evaluate the value of the SpinEdit will be copied to the ProgressBar. You can make the same call to refresh the value, but you can also abstract the concept by indicating to the bindings architecture that the value property of the spin edit has changes. The system will automatically determine if there is one or more expressions involving the property and refresh it:
This change of perspective (a value has changed rather than an expression needs to be recalculated) is of a fundamental importance, as it fully abstracts the data model from the UI it is associated with. We'll get to it, but let me show the simple application UI first:
In this code MyObj is an object of the TMyObject class. Its Name property is associate with the edName component Text. Again, refreshing the expression updates the output. But the object should have no knowledge of the user interface controls or the UI bindings. In fact, all you need to do to instrument the object is to notify the system that the value has changed:
With this code, when the data changes, the UI refreshes automatically to reflect it:
I'm not 100% sure how you want to call the patterns implemented with bindings in Delphi, but it certainly offers a complete separation and abstraction of the data model with the user interface view.
May 28, 2021 by Marco Cantu
Continuing last week blog post on binding expressions, let's see how components can participate, but creating expressions that refer to properties.
Last week I introduced Delphi RTL expression engine in the blog post at Для просмотра ссылки Войди
Binding Two Components
In practical terms, suppose you have a form with a SpinEdit and a ProgressBar. A managed binding allows you to provide an input expression (with one or more input objects) and an output expression (again with one or more objects). As you can see in the code below, each object is associate to the expression providing a name, like spin1 for the SpinEdit1 component, and the expression can refer to the object and its properties, as in spin1.Value. The same happens for the output. You can also specify an output converter, which I've omitted here:
Код:
BindingExpression1 := TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([
Associate(SpinEdit1, 'spin1')
])],
'spin1.Value',
{ outputs }
[TBindings.CreateAssociationScope([
Associate(ProgressBar1, 'progress')
])],
'progress.Position',
{OutputConverter}
nil);
Код:
procedure TFormBindings.SpinEdit1Change(Sender: TObject);
begin
TBindings.Notify(Sender, 'Value');
end;
Binding Objects and UI Controls
This is better explained in the second part of the example, which has an edit box bound to an object in memory. The TMyObject class has a Name and a Value property. Here is how you can bind an object to the UI:
Код:
BindingExpressionObj := TBindings.CreateManagedBinding(
{ inputs }
[TBindings.CreateAssociationScope([
Associate(MyObj, 'obj')
])],
'obj.Name',
{ outputs }
[TBindings.CreateAssociationScope([
Associate(edName, 'edit')
])],
'edit.Text',
{OutputConverter}
nil);
Код:
procedure TMyObject.SetName(const Value: string);
begin
FName := Value;
TBindings.Notify(self, 'Name');
end;
Код:
procedure TFormBindings.btnUpdateObjClick(Sender: TObject);
begin
myobj.Name := myobj.Name + 'Monkey';
end;