XE3 Visual LiveBindings: User defined objects

by Dec 11, 2012

The adapter components TListBindSourceAdapter and TObjectBindSourceAdapter enable LiveBindings with user defined TObjects.

Here is a user defined TObject  for example.

type
TContact = class
private
FFirstName: string
FLastName: string
public
constructor Create overload
constructor Create(const AFirstName, ALastName: string) overload
property FirstName: string read FFirstName write FFirstName
property LastName: string read FLastName write FLastName
end

function LoadContacts: TList<TContact>

implementation

function LoadContacts: TList<TContact>
begin
Result := TObjectList<TContact>.Create
// TODO: Load data from file
Result.Add(TContact.Create('Adam', 'Barns'))
Result.Add(TContact.Create('Chris', 'Decker'))
Result.Add(TContact.Create('Emma', 'Fisk'))
end

One way to use TListBindSourceAdapter is to instantiate the adapter at run time.  Drop a TAdapterBindSourceAdapter on the form and implement the CreateAdapter event as follows:

mplementation

{$R *.dfm}

uses ContactsUnit, System.Generics.Collections

procedure TForm1.AdapterBindSource1CreateAdapter(Sender: TObject
var ABindSourceAdapter: TBindSourceAdapter)
begin
ABindSourceAdapter := TListBindSourceAdapter<TContact>.Create(Self,
LoadContacts)
endi

In the LiveBindings designer, we won't see the fields for TContact because the TContact type is not known at design time.

Drop a TStringGrid on the form and connection the '*' of AdapterBindSource1 to StringGrid1.

A navigator can be added by right clicking AdapterBindSource1 and choosing "Add Navigator".

The grid is populated when the application is run:

A TDataGeneratorAdapter can be used to provide some fields to use at design time.  Add fields with the same name as the properties in TContact.  Set AdapterBindSource1.Adapter to DataGeneratorAdapter1.

The form shows sample data and the LiveBindings designer shows field names.

To show this data at design time, the TDataGeneratorAdapter fields have FieldType: ftString and Generator: LoremIpsum.

The LiveBindings designer can be used to connect fields to controls.

Note that an easy way to create a TLabeledEdit is to right click on FirstName then choose "Link to new control…".

At runtime, the TListBindSourceAdapter will be used instead of DataGeneratorAdapter1 because of the CreateAdapter event.

Another way to use TListBindSourceAdapter is to register a custom component.  Instead of instantiating a TListBindSourceAdapter in the CreateAdapter event, the custom component is dropped from the tool palette.  A TDataGeneratorAdapter is not needed.

The minimal code to for a custom adapter looks like this:

unit ContactsAdapter

interface

uses ContactsUnit, Data.Bind.ObjectScope, System.Classes, System.Generics.Collections

type

TContactsAdapter = class(TListBindSourceAdapter<TContact>)
public
constructor Create(AOwner: TComponent) override
end

implementation

{ TContactsAdapter }

constructor TContactsAdapter.Create(AOwner: TComponent)
begin
inherited Create(AOwner)
SetList(LoadContacts)
end

To register the custom adapter, you will need to create and register a package which contains the custom adapter component and TContact class.  You will also need and a Register method to register the custom component.

unit ContactsAdapterReg

interface

procedure Register

implementation

uses System.Classes, ContactsAdapter, ContactsAdapter2

procedure Register
begin
RegisterComponents('Test', [TContactsAdapter])
end

end.

A complete implementation of a custom adapter publishes properties and methods:

  TContactsAdapter2 = class(TListBindSourceAdapter<TContact>)
public
constructor Create(AOwner: TComponent) override
published
property OnBeforeSetList
property OnAfterSetList
property OnListAppend
property OnListDelete
property OnListInsert
property OnCreateItemInstance
property OnInitItemInstance
property Options
property AutoEdit
property BeforeOpen
property AfterOpen
property BeforeClose
property AfterClose
property BeforeInsert
property AfterInsert
property BeforeEdit
property AfterEdit
property BeforePost
property AfterPost
property BeforeCancel
property AfterCancel
property BeforeDelete
property AfterDelete
property BeforeScroll
property AfterScroll
property BeforeRefresh
property AfterRefresh
property BeforeApplyUpdates
property AfterApplyUpdates
property BeforeCancelUpdates
property AfterCancelUpdates
property OnDeleteError
property OnInsertError
property OnEditError
property OnPostError
property OnApplyUpdatesError
property OnCancelUpdatesError
property OnApplyUpdates
property OnCancelUpdates
property OnHasUpdates
end

TObjectBindSourceAdapter is used instead of TListBindSourceAdapter to bind to a single object, rather than a list of objects.

TObjectBindSourceAdapter is instantiated like this:

procedure TForm1.AdapterBindSource1CreateAdapter(Sender: TObject
var ABindSourceAdapter: TBindSourceAdapter)
begin
ABindSourceAdapter := TObjectBindSourceAdapter<TContact>.Create(Self,
TContact.Create('Adam', 'Barns'))
end

At run time, there is only a single row of data.

Source forge samples

https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE3/LiveBindings/observers

  • ContactsAdapterPackage.dpk

    • Implements a custom TListBindSourceAdapter component

  • ListAdapterEventProject.dpr

    • Demonstrates  TAdapterBindSource.CreateAdapter event

  • ListAdapterComponentProject.dpr

    • Demonstrates custom TListBindSourceAdapter component

  • Project: CppListAdapterEventProject.dpr

    • Cpp project demonstrates  TAdapterBindSource.CreateAdapter event