Skip to content

LiveBindings: FillList using enumerable objects

The previous post introduced a utility method called FillList and showed how to call it using BindScopeDB1 as the source component.  TBindScopeDB allows TBindList to work with a TDataSet.

This post shows a version of FillList which can work with enumerable objects such at TStrings or TList<> (an object is enumerable if it implements GetEnumerator).   TBindScope is used instead of TBindScopeDB.  

Here is a FillList method which can populate a list control from an enumerable object: 

procedure FillList(AControl: TComponent; const AControlExpression: string;
  AEnumerableObject: TObject; const ASourceExpression: string); overload;
var
  LBindList: TBindList;
  LBindScope: TBindScope;
  I: Integer;
begin
  LBindScope := TBindScope.Create(nil);
  LBindList := TBindList.Create(nil);
  try
    // Turn off auto properties.
    LBindList.AutoFill := False;
    LBindList.AutoActivate := False;
    LBindList.ControlComponent := AControl;
    // Scope references the enumerable object
    LBindScope.DataObject := AEnumerableObject;
    LBindList.SourceComponent := LBindScope;
    with LBindList.FormatExpressions.AddExpression do
    begin
      SourceExpression := ASourceExpression;
      ControlExpression := AControlExpression;
    end;
    LBindList.FillList;
  finally
    LBindList.Free;
    LBindScope.Free;
  end;
end;

Call FillList as follows to populate a ListBox or ComboBox with the values from a TStrings:

procedure ListStrings(AListControl: TControl);
var
  LStrings: TStrings;
begin
  LStrings := TStringList.Create;
  try
    LStrings.DelimitedText := 'one,two,three,four,five,six';

    FillList(AListControl, 'Text', LStrings, 'Current');
  finally
    LStrings.Free;
  end;
end;

‘Text’ references the list item text.   ’Current’ references the property Current of TStringsEnumerator.

Instead of TStrings we can also use a generic collection of string:

procedure ListStrings(AListControl: TControl);
var
  LStrings: TList<string>;
begin
  LStrings := TList<string>.Create;
  try
    LStrings.AddRange(
     TArray<string>.Create('one','two','three'));

    FillList(AListControl, 'Text', LStrings, 'Current');
  finally
    LStrings.Free;
  end;
end;

And also a generic collection of object:

type
  TSampleObject = class
  private
    FStringProp: string;
    FIntegerProp: Integer;
  public
    constructor Create(AIntegerProp: Integer);
    property StringProp: string read FStringProp;
    property IntegerProp: Integer read FIntegerProp;
  end;

procedure ListSampleObjects(AListControl: TControl);
var
  LList: TList<TSampleObject>;
  I: Integer;
begin
  LList := TObjectList<TSampleObject>.Create; // Owns objects
  try
    for I := 1 to 10 do
      LList.Add(TSampleObject.Create(I));

    FillList(AListControl, 'Text', LList, 'ToStr(Current.IntegerProp) + ": " + Current.StringProp');
  finally
    LList.Free;
  end;
end;

As mentioned in the previous post,  you will need to use FMX.Binding.Editors. For VCL projects, use VCL.Binding.Editors.

A sample project using FillList is available on sourceforge:

{ 1 } Comments

  1. Ricardo Pascoal | November 18, 2011 at 5:43 am | Permalink

    Hi Jim !

    First of all, thanks for live bindings. I didnt use it yet, but I notice that a great feature.

    But, I think that most interesting you to do some examples closer reality developers, like binding Business Objects persisting it with DBWare and not DBware components.

    make some example like a simple class TPerson or TCustomer persisting in some database like Firebird.

    Try do it ! I think people will like it !

    Best regards

Post a Comment

Your email is never published nor shared. Required fields are marked *

Bad Behavior has blocked 26 access attempts in the last 7 days.

Close