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.
If you take a look at TMemo
source code you will see that Lines
property is defined differently as your Lines
property
property Lines: TStrings read FLines write SetLines;
As you can see TMemo
lines property relies on the use of writer method instead of directly writing to FLines field as you do in your code.
In that SetLines
writer method TStrings.Assign method is called.
procedure TCustomMemo.SetLines(Value: TStrings);
begin
FLines.Assign(Value);
end;
Using this method a copy of the strings from source is made to its destination.
The way how you code is set you simply assign the reference of the source TLines
object to your flines
field making both objects to share same TLines
object. This is extremely dangerous because if the source object gets destroyed your objects ends up referencing to a no longer existing data which could lead to a whole lot of problems.
Fix your Lines
property to match the design from TMemo and this should solve your problem
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.