【问题标题】:Delphi bidirectional binding for Synedit用于 Synedit 的 Delphi 双向绑定
【发布时间】:2019-08-17 10:58:19
【问题描述】:

我需要将 Synedit 双向绑定到数据库中的“文本”列。它适用于备忘录组件,但对于 Synedit 或即 Richedit 仅创建单向绑定。 值是从数据库同步的,但我不知道如何从 Synedit 更新回数据库。

我尝试在 Livebinding 设计器中使用图片上的简单连接字段,但我被困在文档中。

当我离开编辑器时,我需要自动同步数据库字段,就像它与备忘录组件一样。

【问题讨论】:

    标签: delphi livebindings


    【解决方案1】:

    TSynMemo 的行为不像 TMemo 的原因是“开箱即用”它不支持 LiveBindings observers 使LB工作所必需的。克服这个问题的方法是派生一个 TSynMemo 确实支持 LB 观察者并改用它的后代。

    幸运的是,有一个Embarcadero wiki entry 它解释了如何将 LB 观察者添加到缺少它们的组件中。在此基础上,稍作准备, 示例代码应该做你想做的:

    • 在一个新表单上,放置一个 TClientDataSet、TDataSource、TDBGrid 和一个 TDNavigator,并以通常的方式将它们链接起来。使用 TClientDataSet 是为了允许一个完全自包含的示例项目。 注意如果你想使用 FireDAC。您同样可以使用 TFDMemTable 而不是 TClientDataSet;下面的步骤和代码将是相同的,我已经测试过这个 FD 替代方案是否有效。

    • 在 TClientDataSet 上设置 ID、Name (String(20)) 和 Memo 字段,如代码所示

    • 将通过 TDataSource 连接的 TBSynEdit 添加到备注字段。这样做的目的 是为了显示我们接下来要添加的实时绑定的 TSynMemo 以相同的方式执行

    • 向表单添加 TSynMemo、TMemo、TBindingList、TBindSourceDB 和 TBindNavigator

    • 使用快速绑定弹出窗口添加 TLinkControlToFields 以链接 TSynEdit 和 TMemo 到 ClientDataSet 的 Memo 字段

    • 将 BindSourceDB 的 * 属性连接到可视 LB 设计器中 TBindNavigator 的 * 属性。

    现在,将以下代码添加到表单中。为了省去注册我们的 TSynMemo 后代作为组件并安装在IDE中,代码声明它 在表单单元中作为Interposer class。它实现了所有的观察方法 这似乎是实时绑定 TSynMemo 所必需的。

    代码

      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.
    

    【讨论】:

    • 很抱歉,我也无法重现它,因为我正在使用 TFDconnection 和 TFDtable。你能分享这个项目吗?我知道我需要 Interposer 以及如何创建,但是您在主机中进行并使用 livebinding 设计器?
    • 使用 FireDAC 组件应该不会影响这个答案是否有效。当您说“但是您在主机中执行并使用实时绑定设计器?”时,我不明白您在问什么?
    • 对不起我的英语。所有这些代码都在主机中吗?我可以使用 Livebinding 设计器创建这种双向连接吗?因为它对我不起作用。
    • 我刚刚更新了代码以将 TClientDataSet 替换为 TFDMemTable,将 BindSourceDB1 更改为指向它,该项目仍然可以正常工作,所以如果您能接受这个答案,我将不胜感激(通过单击“勾号”图标),因为它确实回答了您发布的问题。如果您在将其应用于 FDTable 时遇到问题,您应该发布一个新的 q 来询问这个问题。
    • 是的,所有代码都在主单元中,正如代码清楚地显示的那样。你问的是哪个双向连接?如果您完全按照我的答案中的步骤创建一个新项目,它将“正常工作”。
    猜你喜欢
    • 2018-05-14
    • 2014-07-03
    • 2011-10-07
    • 2020-06-03
    • 1970-01-01
    • 2015-04-26
    • 2016-04-19
    • 2012-05-25
    • 1970-01-01
    相关资源
    最近更新 更多