XE3 Visual LiveBindings: Link controls to fields

By: Tim DelChiaro

Abstract: Blog post from Jim Tierney

This is a copy of a blog post from http://blogs.embarcadero.com/jimtierney/2012/10/01/31653. If you have comments or feedback, please post the comments on the original blog post.

    XE3 Visual LiveBindings: Link controls to fields

One type of link supported by Visual LiveBindings is between simple controls and data source fields.   Simple controls are visual components which accept user input to edit a value.  TEdit and TCheckBox are examples of simple controls.

The first part of this post describes how to link controls to data source fields using the LiveBindings designer.   The second part describes how to LiveBindings-enable a control.

You can find the code from this post on sourceforge:https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE3/LiveBindings/observers/vcl

    Link controls to a data source fields

After a TEdit and TCheckBox are dropped on a VCL, the controls are represented in the  LiveBindings designer (View\LiveBindings designer).  The TEdit is shown with the member "Text" and TCheckBox with the member "Checked".  These are the control members changed by user input.

The LiveBindings designer can be used to connect these members to data source fields.

The TPrototypeBindSource component is an easy way to create a data source.  Drop a TPrototypeBindSource on the form.  Right click on it and choose "Add Field…"

Choose a boolean, integer and string field as shown below.  You can multiselect the fields or add them one at a time.

The LiveBindings designer shows PrototypeBindSource1 and the new fields:

You can connect the members of the controls to the fields.  Note that when a member is selected, other members change color.  Green indicates which members can connect.


You can connect them like this (use the rearrange button to get this spacing):

Or try different connections.  If LiveBindings can’t convert between the control member type and field type, an error message box is displayed.  To switch the links, grab the arrow and move it to another member.  If you want to get rid of a link, right click on a line and choose "Remove Link".  Multiple controls can link to the same field. But a particular control can only link to one field.  If you try to add an additional link to a control, a message box will prompt you about deleting the existing link.

You can add a navigator control by right clicking on the TPrototypeBindSource (in the form designer not the LiveBindings designer) and choosing Add Navigator.  Now the app is ready to run.

    LiveBindings-enable a control

If you drop a TTrackBar on the form, the LiveBindings designer will display the Trackbar like this:

Notice that the LiveBindings designer doesn’t show  a member for TrackBar1.   This is because TTrackBar is has not been enabled for LiveBindings.

There are two requirements to  LiveBindings-enable a simple control like TTrackBar.  The first requirement is that the control implement observer support.  LiveBindings depends on observers to subscribe to control notifications.   The second requirement is to register the control value name (e.g.; "Position" for TTrackBar). The control value name is used by LiveBindings components to generate expressions which get and set the control’s value.

We can’t directly modify TTrackbar, so observer support must be implemented in a descendent class.  I’ve named this class TObservableTrackbar and the unit VCL.Sample.ObservableTrackbar.   Here is the interface section:

unit VCL.Sample.ObservableTrackbar;

interface

uses Vcl.ComCtrls, System.Classes, WinApi.Messages, WinApi.CommCtrl, Vcl.Controls;

type

  [ObservableMember('Position')]
  TObservableTrackBar = class(TTrackBar)
  private
    procedure CNHScroll(var Message: TWMHScroll); message CN_HSCROLL;
    procedure CNVScroll(var Message: TWMVScroll); message CN_VSCROLL;
    procedure ObserverToggle(const AObserver: IObserver; const Value: Boolean);
  protected
    function CanObserve(const ID: Integer): Boolean; override;
    procedure ObserverAdded(const ID: Integer; const Observer: IObserver);  override;

  end;

implementation

uses System.SysUtils;

I’ve included both uses lists in this code snippet to show that there are no references to  LiveBindings units. The declarations of observer interfaces, etc. are in System.Classes.

The ObservableMember attribute identifies the control value name for TObservableTrackbar:

  [ObservableMember('Position')]
  TObservableTrackBar = class(TTrackBar)

Controls which implement observers always override TComponent.CanObserve().  This method identifies the type of observers supported by TObservableTrackbar.

function TObservableTrackBar.CanObserve(const ID: Integer): Boolean;
begin
  case ID of
    TObserverMapping.EditLinkID,
    TObserverMapping.ControlValueID:
      Result := True;
  else
    Result := False;
  end;
end;

EditLinkID is the observer that is used for control-to-field links.

The overrides for CNHscroll and CNVScroll are where TObserverableTrackBar calls the observable interfaces to notify LiveBindings components when the user moves the thumb.

procedure TObservableTrackBar.CNHScroll(var Message: TWMHScroll);
var
  LPosition: Integer;
begin
  LPosition := Position;
  inherited;
  if LPosition <> Position then
    TLinkObservers.ControlChanged(Self);
end;

procedure TObservableTrackBar.CNVScroll(var Message: TWMVScroll);
var
  LPosition: Integer;
begin
  Message.Result := 0;
  LPosition := Position;
  inherited;
  if LPosition <> Position then
    TLinkObservers.ControlChanged(Self);
end;

These two overrides are sufficient to monitor user input to TObservableTrackbar. TLinkObservers.ControlChanged is a utility method that does most of the work.  You can find the implementation in System.Classes.

The following methods prevent the user from moving the thumb when TObservableTrackBar is linked to a read-only field.

procedure TObservableTrackBar.ObserverAdded(const ID: Integer;
  const Observer: IObserver);
begin
  if ID = TObserverMapping.EditLinkID then
    Observer.OnObserverToggle := ObserverToggle;
end;

procedure TObservableTrackBar.ObserverToggle(const AObserver: IObserver;
  const Value: Boolean);
var
  LEditLinkObserver: IEditLinkObserver;
begin
  if Value then
  begin
    if Supports(AObserver, IEditLinkObserver, LEditLinkObserver) then
      // Disable the trackbar if the associated field does not support editing
      Enabled := not LEditLinkObserver.IsReadOnly;
  end
  else
    Enabled := True;
end;

All controls which support the EditLink observer, should prevent the user from changing the control value. Disabling the control is one way to do it.  Some observer implementations ignore certain types of input to prevent the user from changing the control value.

On more piece of code is needed to make TObservableTrackBar fully enabled in the LiveBindings designer. The control value name property must be registered using RegisterObservableMember().  This code can go in the same unit which registers the component:

unit VCL.Sample.ObservableTrackbarReg;

interface

procedure Register;

implementation

uses System.Classes, VCL.Sample.ObservableTrackbar, Data.Bind.Components;

procedure Register;
begin
  RegisterComponents('LiveBindings Samples', [TObservableTrackBar]);
end;

initialization
  Data.Bind.Components.RegisterObservableMember(TArray<TClass>.Create(
    TObservableTrackBar),
    'Position', 'DFM');
finalization
  Data.Bind.Components.UnregisterObservableMember(TArray<TClass>.Create(
    TObservableTrackBar));
end.

"Position" is identified as the control value name in two places–in  VCL.Sample.ObservableTrackbar .pas with the ObservableMember attribute and in VCL.Sample.ObservableTrackbarReg .pas by calling RegisterObservableMember().  The ObserverbleMember attribute will be used by LiveBindings components to generate expressions.  RegisterObserverableMember() will be used at design time to inform the LiveBindings designer.

After installing a package which contains VCL.Sample.ObservableTrackbar and VCL.Sample.ObservableTrackbarReg, TObservableTrackbar can be selected from the component palette. TObservableTrackbar is represented in the LiveBindings designer like this:

ObservableTracker1.Position can be connected to a field using the LiveBindings designer.  The following connections include a TEdit so that, when the app is run, you see the value of the field as the thumb is moved:

The default Min and Max values for the TObservableTrackBar are 0 and 10.  The data generated by TPrototypeBindSource is out of this range.  Modify Min and Max in the object inspector to -100 and 100.

The LiveBindings designer has a command to create the control and connect to a field in one step.  This command is available if you right click on a field in the LiveBindings designer.

"Link to new control…" displays a list the controls which have been registered by RegisterObserverableMember().  Scroll down to find TObservableTrackBar.

In addition to linking to fields, TObserverTrackBar can link to component properties.  I’ll write about linking simple controls to component properties next time.

Server Response from: ETNASC01