delphilivebindings

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 i.e. 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.

scheme binding

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


Solution

  • 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:

    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.