使用 TPrototypeBindSource 自动更新对象中的属性

Using TPrototypeBindSource to automatically update properties in an object

我正在尝试使用实时绑定来更新我的(非组件)对象的属性。我有一个 TPrototypeBindSource,我用它来将组件绑定到我的对象字段,并在 运行 时间使用 TObjectBindSourceAdapter。如果在编辑组件的 onchange 事件中调用 MyPrototypeBindSource.Refresh,我可以让它工作,但是有没有办法让它自动发生,而不需要为我的表单上的每个组件设置 onchange 事件?

虽然有 TPrototypeBindSource.AutoPost,我 suspect 来处理自动 post 控制数据到数据对象,但它没有……好好看看源代码,这个属性 只影响内部数据生成器。

似乎是,我们必须在创建适配器时手动设置此 属性(因为我们就在此时我们将设置 AutoEdit):

procedure TForm1.PrototypeBindSource1CreateAdapter( Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter );
begin
  FPerson := TPerson.Create;
  ABindSourceAdapter := TObjectBindSourceAdapter<TPerson>.Create( Self, FPerson );
  ABindSourceAdapter.AutoEdit := True;
  ABindSourceAdapter.AutoPost := True;
end;

每次你 离开 一个 TEdit 但一个 TCheckBox 将立即 post 数据。

要更改此设置,只需使用 published 方法

procedure TForm1.ControlChanged( Sender: TObject );
begin
  if Sender is TComponent
  then
    TLinkObservers.ControlChanged( Sender as TComponent );
end;

并将其分配给每个需要的控件(例如TEdit.OnChange)以立即将数据获取到数据对象。

这里一网打尽

type
  TPerson = class
  private
    FFirstname: string;
    FLastname: string;
    FActive: Boolean;
  public
    function ToString: string; override;

    property Active: Boolean read FActive write FActive;
    property Firstname: string read FFirstname write FFirstname;
    property Lastname: string read FLastname write FLastname;
  end;

  TForm1 = class( TForm )
    PersonSource: TPrototypeBindSource; { OnCreateAdapter -> PersonSourceCreateAdapter }
    Edit1: TEdit; { OnChange -> ControlChanged }
    Edit2: TEdit; { OnChange -> ControlChanged }
    BindingsList1: TBindingsList;
    LinkControlToField1: TLinkControlToField;
    LinkControlToField2: TLinkControlToField;
    Label1: TLabel;
    ApplicationEvents1: TApplicationEvents; { OnIdle -> ApplicationEvents1Idle }
    CheckBox1: TCheckBox;
    LinkControlToField3: TLinkControlToField;
    procedure PersonSourceCreateAdapter( Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter );
    procedure ApplicationEvents1Idle( Sender: TObject; var Done: Boolean );
  private
    FPerson: TPerson;
  published
    procedure ControlChanged( Sender: TObject );
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ApplicationEvents1Idle( Sender: TObject; var Done: Boolean );
begin
  // just for checking then object data
  Label1.Caption := FPerson.ToString;
end;

procedure TForm1.ControlChanged( Sender: TObject );
begin
  if Sender is TComponent
  then
    TLinkObservers.ControlChanged( Sender as TComponent );
end;

procedure TForm1.PersonSourceCreateAdapter( Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter );
begin
  FPerson := TPerson.Create;
  ABindSourceAdapter := TObjectBindSourceAdapter<TPerson>.Create( Self, FPerson );
  ABindSourceAdapter.AutoEdit := True;
  ABindSourceAdapter.AutoPost := True;
end;

{ TPerson }

function TPerson.ToString: string;
begin
  Result := FLastname + ', ' + FFirstname + ' ' + BoolToStr( FActive );
end;

LiveBindings:

Active    : ftBoolean -> CheckBox1/CheckedState(Self)
Firstname : ftString  -> Edit1/Text
Lastname  : ftString  -> Edit2/Text

如果您不喜欢将 ControlChanged 方法分配给所有控件,您可以通过调用 TPrototypeBindSource.Post 强制 TPrototypeBindSource 到 post 数据。但是你必须先检查它是否处于编辑模式:

if PersonSource.Editing
then
  PersonSource.Post;

每当您需要 posted 数据时调用它...如果在任何时候只需在 TApplicationEvents.OnIdle.

内调用它