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

最佳答案

尽管有TPrototypeBindSource.AutoPost由我suspect处理来将控制数据自动发布到数据对象,但是它并不能很好地查看源代码,但是此属性只会影响内部数据生成器。

似乎是,我们在创建适配器时必须手动设置此属性(并且由于我们此时也将设置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

If you do not like to assign the ControlChanged method to all controls you can force the TPrototypeBindSource to post the data by calling TPrototypeBindSource.Post. But you have to check first if it is in edit mode:

if PersonSource.Editing
then
  PersonSource.Post;


每当您需要发布数据时都可以调用此方法……如果随时可以在TApplicationEvents.OnIdle中调用它。

09-28 03:01