Подтвердить что ты не робот

Нужно двунаправленное LiveBindings между элементом управления и объектом

В Delphi XE2 LiveBindings мне нужно привязать элемент управления VCL любого типа к свойству любого типа на произвольном (некомпонентном) объекте. Я могу сделать это односторонне. Но мне нужно сделать это в двух направлениях.

Скажем, я хочу привязать строку TPerson.PersonName: к TEdit.Text.

То, что у меня сейчас, простое.

  • Создайте новое приложение VCL, добавьте TBindScope, TBindingsList, TEdit.
  • Создайте экземпляр TPerson с именем person1.
  • Используя BindingList, добавьте свойство TBindExpression.
  • С BindExpression
    • установить ControlComponent в Edit1
    • установите ControlExpression в "Текст"
    • установить SourceComponent в BindScope1
    • установить SourceExpression в PersonName
  • Добавить кнопку; к событию Click Я добавляю: BindScope1.DataObject: = person1;
  • Добавить кнопку; к событию Click, которое я добавляю (требуется только один, но пока он не будет работать, я попробую их оба).
    • TBindings.Notify(отправитель, '');
    • BindingsList1.Notify(отправитель, '');

Первая кнопка связывается в первом направлении. Вторая кнопка никогда не возвращает значение обратно в свойство person1.PersonName.

Я экспериментировал с кодом уведомления, направлением привязки, типами привязки, выражениями, SourceMember и т.д. Иногда я получаю ошибки времени выполнения в конфигурации bindexpression, а остальное время привязка просто однонаправленная.

Я ожидаю щелкнуть вторую кнопку и увидеть содержимое Edit1.Text, написанное для person1.PersonName.

Если мне нужно сделать все это из кода, я буду рассматривать его, и такие примеры приветствуются, но я действительно хочу сделать это через конструктор, если это возможно.

Обратите внимание, что мне не интересно связывать два элемента управления.

Обратите внимание, что я уже загрузил и просмотрел примеры проектов LiveBinding и не нашел ничего такого. Если это неверно, будьте конкретны, указав это. Я также прочитал DocWiki. Он не охватывает двунаправленную привязку, за исключением использования элементов управления DB LiveBinding. Я не использую элементы управления DB LiveBinding и не использую DataSet. Поэтому, если вы не можете объяснить мне, почему я должен их использовать, мне не нужна информация об этих элементах управления.

4b9b3361

Ответ 1

Теперь у меня это работает. Я сделал все это в дизайнере, но преобразовал его в основном код, чтобы лучше делиться им с SO.

Создайте проект форм VCL. В форме отбросьте каждый из них по форме:

TBindScope TBindingsList TButton TButton TEdit

Переименуйте одну из кнопок в btnLoad, а другую - в btnSave.

Вставьте этот код в блок формы (при условии, что он называется Form1). Назначьте обработчики кликов для кнопок и запустите их. Нажмите btnLoad, чтобы заполнить поле редактирования данными объекта TPerson, отредактируйте текст в поле редактирования до нового значения, затем нажмите btnSave, чтобы записать его обратно в объект TPerson.

unit Form1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Rtti,

  // LiveBinding units
  System.Bindings.Helper,     // Contains TBindings class
  Data.Bind.EngExt,
  Vcl.Bind.DBEngExt,
  Data.Bind.Components,
  System.Bindings.Outputs;

type
  TPerson = class(TObject)
  protected
    fName: string;
    fAge: integer;
    procedure SetName(const Value: string);
  public
    property Name: string read fName write SetName;
    property Age: integer read fAge write fAge;
  end;

type
  TForm1 = class(TForm)
    btnLoad: TButton;
    btnSave: TButton;
    BindScope1: TBindScope;
    BindingsList1: TBindingsList;
    Edit1: TEdit;
    procedure btnLoadClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
  private
    fInitialized: boolean;
    fPerson: TPerson;
    procedure Initialize;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.AfterConstruction;
begin
  inherited;
  Initialize;
end;

procedure TForm1.BeforeDestruction;
begin
  fPerson.Free;
  inherited;
end;

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  fPerson.Name := 'Doogie Howser';
  fPerson.Age := 15;
  BindScope1.DataObject := fPerson;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  TBindings.Notify(Edit1, '');

  // Could also do this:
  //BindingsList1.Notify(Edit1, '');
end;

procedure TForm1.Initialize;
var
  expression: TBindExpression;
begin
  // Create a binding expression.
  expression := TBindExpression.Create(self);
  expression.ControlComponent := Edit1;
  expression.ControlExpression := 'Text';   // The Text property of Edit1 ...
  expression.SourceComponent := BindScope1;
  expression.SourceExpression := 'Name';    // ... is bound to the Name property of fPerson
  expression.Direction := TExpressionDirection.dirBidirectional;

  // Add the expression to the bindings list.
  expression.BindingsList := BindingsList1;

  // Create a Person object.
  fPerson := TPerson.Create;
end;

{ TPerson }

procedure TPerson.SetName(const Value: string);
begin
  fName := Value;
  ShowMessage('Name changed to "'+ Value +'"');
end;

end.