Нужны двунаправленные LiveBindings между элементом управления и объектом - PullRequest
19 голосов
/ 20 сентября 2011

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

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

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

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

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

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

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

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

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

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

1 Ответ

16 голосов
/ 22 сентября 2011

У меня сейчас работает. Я сделал все это в конструкторе, но преобразовал его в основном в код, чтобы лучше делиться им в 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.
...