简体   繁体   中英

Delphi bidirectional binding for Synedit

I need to bi-directionaly bind Synedit to column 'text' in database. It works with memo component, but for Synedit or ie Richedit is created only one-directional binding. Value is synchronized from database, but i don't know how to update back to database from Synedit.

I try in the Livebinding designer simple connect fields like on picture, but it i'm stuck in documentation.

方案捆绑

I need automatically synchronized database field when i leave editor, like it works with Memo component.

The reason that TSynMemo does not behave like TMemo is that 'out of the box' it has no support the LiveBindings observers necessary to make LB work. The way to overcome this is to derive a TSynMemo descendent which does support LB observers and use that instead.

Luckily, there is an Embarcadero wiki entry which explains how to add LB observers to components which lack them. Based on that, with a little preparatory settting up, the example code should do what you want:

  • On a new form, drop a TClientDataSet, TDataSource, TDBGrid and a TDNavigator and link them up in the usual way. Using a TClientDataSet is to allow a completely self-contained sample project. Note If you want to use FireDAC. you can equally well use a TFDMemTable instead of a TClientDataSet; the steps and code below will be identical, and I've tested that this FD alternative works.

  • Set up ID, Name (String(20)) and Memo fields on the TClientDataSet as shown in the code

  • Add a TBSynEdit connected via the TDataSource to the Memo Field. The purpose of this is to show that the live-bound TSynMemo which we'll add next performs in the same way

  • Add a TSynMemo, TMemo, TBindingList, TBindSourceDB, and TBindNavigator to the form

  • Use the quick-binding pop-up to add TLinkControlToFields to link the TSynEdit and the TMemo to the Memo field of the ClientDataSet

  • Connect the * property of the BindSourceDB to the * property of the TBindNavigator in the visual LB designer.

Now, add the code below to the Form. To save having to register our TSynMemo descendant as a component and install it in the IDE, the code declares it in the form unit as an Interposer class . It implements all the obsever methods that seem to be necessary to live-bind a TSynMemo.

Code

  type
    TSynMemo = class(SynMemo.TSynMemo)
    private
      procedure ObserverToggle(const AObserver: IObserver; const Value: Boolean);
    protected
      procedure DoChange; override;
      function CanObserve(const ID: Integer): Boolean; override;                       { declaration is in System.Classes }
      procedure ObserverAdded(const ID: Integer; const Observer: IObserver); override; { declaration is in System.Classes }
    end;

    TForm2 = class(TForm)
      ClientDataSet1: TClientDataSet;
      DataSource1: TDataSource;
      DBGrid1: TDBGrid;
      DBNavigator1: TDBNavigator;
      SynMemo1: TSynMemo;
      ClientDataSet1ID: TIntegerField;
      ClientDataSet1Name: TStringField;
      ClientDataSet1Memo: TMemoField;
      BindingsList1: TBindingsList;
      BindNavigator1: TBindNavigator;
      Memo1: TMemo;
      BindSourceDB1: TBindSourceDB;
      LinkControlToField1: TLinkControlToField;
      LinkControlToField2: TLinkControlToField;
      DBSynEdit1: TDBSynEdit;
      procedure FormCreate(Sender: TObject);
    public
    end;

  [...]implementation[...]

  function TSynMemo.CanObserve(const ID: Integer): Boolean;
  { Controls which implement observers always override TComponent.CanObserve(const ID: Integer). }
  { This method identifies the type of observers supported by TObservableTrackbar. }
  begin
    case ID of
      TObserverMapping.EditLinkID,      { EditLinkID is the observer that is used for control-to-field links }
      TObserverMapping.ControlValueID:
        Result := True;
    else
      Result := False;
    end;
  end;

  procedure TSynMemo.DoChange;
  begin
    inherited;
    TLinkObservers.ControlChanged(Self);
  end;

  procedure TSynMemo.ObserverAdded(const ID: Integer; const Observer: IObserver);
  begin
    if ID = TObserverMapping.EditLinkID then
      Observer.OnObserverToggle := ObserverToggle;
  end;

  procedure TSynMemo.ObserverToggle(const AObserver: IObserver; const Value: Boolean);
  var
    LEditLinkObserver: IEditLinkObserver;
  begin
    EXIT;  //  do nothing
  end;

  const
    sDfm = 'DFM';

  procedure TForm2.FormCreate(Sender: TObject);
  begin
    ClientDataSet1.IndexFieldNames := 'ID';
    ClientDataSet1.CreateDataSet;

    ClientDataSet1.InsertRecord([1, 'Row1', 'Memo1']);
    ClientDataSet1.InsertRecord([2, 'Row2', 'Memo two']);

  end;

  initialization

    Data.Bind.Components.RegisterObservableMember(TArray<TClass>.Create(
      TSynMemo
      ),
      'Lines.Text', sDfm);

  finalization

    Data.Bind.Components.UnregisterObservableMember(TArray<TClass>.Create(TSynMemo));

  end.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM