Delphi 10.4
I have an issue bidirectional Tstrings binding. I have a simple app with 2 controls and a bind source. I am trying to bind bidirectionally a TStrings property of an object to to a TMemo control. I am using a TPrototypeBindSource with a TObjectBindSourceAdapter as the bind source adapter.
I have the lines property on the TPrototypeBindSource set to a ftTStrings fieldtype
TFoo is defined as;
TFoo = class (TObject)
private
Fname: string;
flines: TStrings;
published
constructor Create;
destructor destroy; override;
property name: string read Fname write Fname;
property lines: Tstrings read Flines write Flines;
end;
The Adapter is set with the on create event
procedure TForm1.PrototypeBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
begin
ABindSourceAdapter := TObjectBindSourceAdapter<TFoo>.Create(Self, GetFoo, False);
end;
Using live bindings I have the
PrototypeBindSource name fielddef <---> edit text field. PrototypeBindSource lines fielddef <---> memo text field.
All is good when you are reading or updating the name <-> edit control and when setting the memo text field. It recognises the lines field in the TPrototypeBindSource as being a TStrings.
However, when I change the text in the memo and go to post it back to the TPrototypeBindSource I get this exception
EBindConverterError : unable to cast or find converters between types string and TObject
There is a TStrings to string and string to TStrings converters registered. But there seems a disconnect between the TString in the object and the adapter as it cannot seem to see its type.
Have I missed something or is the RTL got issues?
EDIT:
Thanks, I missed that setter. Even with it fixed the issue remains...
TFoo = class (TObject)
...
procedure SetLines(const aValue: TStrings);
...
end;
procedure TFoo.SetLines(const Value: TStrings);
begin
Flines.Assign(Value);
end;
The converters don't go through the setter they use the TStrings text property
system.bindings.outputs
class procedure TConverterUtils.StringToStrings(const I: TValue; var O: TValue);
var
oOut: TStrings;
begin
oOut := TStrings(O.AsObject);
if oOut <> nil then
begin
if I.IsEmpty then
oOut.Text := ''
else
oOut.Text := I.AsString;
end;
end;
Tracing through the binding code, the converters get called in here
procedure TBindingOutput.SetValue(AExpression: TObject; const ValueFunc: TBindOutValueFunc);
begin
...
if AllowConverter then
CanConvert := ValueConverter.CanConvert(LFinalOutVal.TypeInfo, LocationRec.Location.GetType);
...
end
Which calls;
function TValueRefConverter.CanConvert(AFrom, ATo: PTypeInfo): Boolean;
begin
Result := GetConverter(AFrom, ATo, False) <> nil;
end;
When going from the TStrings property to the Text prop on the TMemo, the TypeInfo for the AFrom shows as a TStringlist, but when it is going back the other way the ATo PTypeInfo shows TObject not TStringList.
As the converters are registered for TStrings it cannot find the appropriate converter.
I got lost trying to work out where the info is stored.