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

时间:2015-01-30 19:06:58

标签: delphi delphi-xe4 livebindings

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

1 个答案:

答案 0 :(得分:4)

虽然有TPrototypeBindSource.AutoPostsuspect来处理控制数据到数据对象的自动发布但它没有......很好地查看源,这个属性只会影响内部数据发生器。

似乎是,我们必须在创建适配器时手动设置此属性(因为我们此时也会设置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;

每次离开 TEditTCheckBox时,这都可以胜任  将立即发布数据。

要更改此设置,只需使用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通过调用TPrototypeBindSource.Post发布数据。但是你必须首先检查它是否处于编辑模式:

if PersonSource.Editing
then
  PersonSource.Post;

每当您需要发布数据时都要调用此信息...如果在任何时候只需在TApplicationEvents.OnIdle内调用它。