1

我正在尝试在 VCL 表单上使用实时绑定,其中要绑定到表单上控件的对象作为属性传递给表单。我正在使用 10.1 柏林。对象中传递的属性是普通的:

 Public
      Property ProjectObject: TProject Read fProjectObject Write fProjectObject;

我已经使用 DataGeneratorAdapter 和 AdapterBindSource 来使用设计器在表单上设置链接。

我缺乏理解的地方是 OnCreateAdapter 方法中的 AdapterBindSource。我能找到的所有示例都显示了如何创建一个由控件填充的新对象,但我找不到在 runtinme fProjectObject(传递的对象)处绑定的方法。

我当前在 OnCreateAdapter 方法中的代码是:

ABindSourceAdapter := TObjectBindSourceAdapter<TProject>.Create(Self);

编译器可以接受,但不允许控件显示和更新 fProjectObject 中的属性。

显示此表单(项目编辑表单)的代码部分之一如下所示:

ProjEdit.ProjectObject := Proj;
ProjEdit.ShowModal;
StoreProject(Proj);

其中ProjEdit是项目编辑表单,ProjectObject是项目对象传入的属性,Proj是要编辑的项目对象。项目对象被简单地传递到此表单并在对信息进行任何更改后存储。此对象在传递给此表单进行编辑之前存储在数据库中。

如何将 livebindings 连接到传递的对象?

在此先感谢您的帮助

4

2 回答 2

1

我认为可能让你绊倒的事情是在事件触发之前需要创建你的 ProjectObject 的不是很明显的一点。CreateAdapter为确保发生这种情况,您需要覆盖表单的 Create 方法并在那里创建您的 ProjectObject。

以下对我来说很好:

type

  TPerson = class
  private
    FLastName: String;
    FFirstName: String;
  public
    property FirstName : String read FFirstName write FFirstName;
    property LastName : String read FLastName write FLastName;
  end;

  TForm1 = class(TForm)
    edFieldA: TEdit;
    edFieldB: TEdit;
    BindNavigator1: TBindNavigator;
    PrototypeBindSource1: TPrototypeBindSource;
    BindingsList1: TBindingsList;
    LinkControlToField1: TLinkControlToField;
    LinkControlToField2: TLinkControlToField;
    procedure PrototypeBindSource1CreateAdapter(Sender: TObject; var
        ABindSourceAdapter: TBindSourceAdapter);
  private
  public
    Person : TPerson;
    constructor Create(AOwner : TComponent);  override;
  end;

[...]

constructor TForm1.Create(AOwner: TComponent);
begin
  Person := TPerson.Create;
  Person.FirstName := 'John';
  Person.LastName := 'Smith';
  inherited;
end;

procedure TForm1.PrototypeBindSource1CreateAdapter(Sender: TObject; var
    ABindSourceAdapter: TBindSourceAdapter);
begin
  ABindSourceAdapter := TObjectBindSourceAdapter<TPerson>.Create(Self, Person, False);
end;

更新表单上的 Person 对象不必在表单上创建。它可以简单地分配给先前存在的对象,如

constructor TForm1.Create(AOwner: TComponent);
begin
  Person := SomeTPersonObjectCreatedAlreadyInOtherCode;
  inherited;
end;

如果您想在我的示例中验证这一点,请在单元的初始化部分创建一个 TPerson 实例,并在表单的Create构造函数中将 Form1.Person 分配给它。您可能没有意识到 Delphi 对象变量实际上是一个指针,因此它可以自由地“指向”对象的现有实例。

重要的是将最后一个参数设置TObjectBindSourceAdapter为False,这样适配器就不会拥有Person对象,否则当它(适配器)被销毁时会销毁Person对象。

顺便说一句,此视频中解释了覆盖表单构造函数的需要:

https://delphiaball.co.uk/2015/10/19/livebindings-in-vcl-part-2-livebinding-objects/

他解释说,如果您没有在 CreateAdapter 事件之前创建要绑定的对象,则绑定将清除该对象在绑定字段中已有的任何内容。

于 2017-03-05T10:40:58.067 回答
1

这是我的建议:

首先:在 AdapterBindSource 的 CreateAdapter 中使用以下内容:

procedure TfrmProjectEdit.AdapterBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
begin
  fProjectObject:=TProject.Create;
  ABindSourceAdapter:=TObjectBindSourceAdapter<TProject>.Create(self, fProjectObject, True);
end;

第二:对项目属性使用设置器,例如:

procedure TfrmProjectEdit.SetProject (aProject: TProject);
begin
  fProjectObject:=aProject;
  AdapterBindSource1.Refresh;
end;

快速解释:AdapterBindSource 将拥有 fProjectObject 并在 ABS 释放时释放它。我们只需为 fProjectObject 分配一个新值并在 setter 中刷新 ABS。

我还没有测试过这段代码 - 但我认为这应该可以工作......

于 2017-03-05T23:35:04.460 回答