2011-09-20 9 views
18

In Delphi XE2 LiveBindings, è necessario associare un controllo VCL di qualsiasi tipo a una proprietà di qualsiasi tipo su un oggetto arbitrario (non componente). Posso farlo unidirezionalmente. Ma ho bisogno di farlo in modo bidirezionale.È necessario il LiveBinding bidirezionale tra un controllo e un oggetto

Diciamo che voglio associare un TPerson.PersonName: stringa a un TEdit.Text.

Quello che ho ora è semplice.

  • Creare una nuova applicazione VCL, aggiungere un TBindScope, TBindingsList, TEdit.
  • Creare un'istanza di TPerson denominata person1.
  • Utilizzando un BindingList, aggiungere una proprietà TBindExpression.
  • Con BindExpression
    • set ControlComponent a Edit1
    • set ControlExpression a 'Testo'
    • set SourceComponent a BindScope1
    • set SourceExpression a PersonName
  • Aggiungi un pulsante; all'evento Click aggiungo: BindScope1.DataObject: = person1;
  • Aggiungi un pulsante; all'evento Click che aggiungo (solo uno è necessario, ma fino a quando funzionerà proverò entrambi).
    • TBindings.Notify (mittente, '');
    • BindingsList1.Notify (mittente, '');

Il primo pulsante lega nella prima direzione. Il secondo pulsante non sembra mai scrivere il valore sulla proprietà person1.PersonName.

Ho sperimentato con il codice di notifica, la direzione di rilegatura, i tipi di binding, le espressioni, SourceMember, ecc. A volte ottengo errori di runtime nella configurazione di bindexpression, il resto del tempo il binding è semplicemente unidirezionale.

Mi aspetto di fare clic sul secondo pulsante e vedere il contenuto di Edit1.Text scritto in person1.PersonName.

Se devo fare tutto questo dal codice, lo prenderò in considerazione e tali esempi sono benvenuti, ma voglio davvero farlo attraverso il designer, se possibile.

Nota che non mi interessa legare tra due controlli.

Nota anche che ho già scaricato e verificato i progetti di esempio di LiveBinding e non ho trovato nessuno che lo faccia. Se questo è sbagliato, per favore sii specifico quando lo fai notare. Ho anche letto il DocWiki. Non copre il binding bidirezionale se non utilizzando i controlli DB LiveBinding. Non sto utilizzando i controlli DB LiveBinding né sto utilizzando un DataSet. Quindi, a meno che tu non possa spiegarmi perché dovrei usarli, non avrò bisogno di alcuna informazione su quei controlli.

+0

Uso DSharp anziché LiveBindings e fare questo due liner (uno per attuare il setter di una proprietà che dovrebbe obbligatorio consapevoli e uno per creare il legame) –

risposta

16

Ho funzionato ora. Ho fatto tutto nel designer, ma l'ho convertito in codice per condividerle meglio su SO.

Creare un progetto di moduli VCL. Nel modulo, goccia ciascuno di questi sulla forma:

TBindScope TBindingsList TButton TButton TEdit

Rinominare uno dei pulsanti per btnLoad e l'altro per btnSave.

Incollare questo codice sull'unità modulo (assumendo che sia denominato Form1). Assegna i gestori di clic per i pulsanti ed eseguilo. Fare clic su btnLoad per popolare la casella di modifica con i dati dell'oggetto TPerson, modificare il testo nella casella di modifica su un nuovo valore, quindi fare clic su btnSave per riscriverlo sull'oggetto 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. 
+0

TBindScope più disponibile come componente temporale del design dal XE6 –

+0

Ma ancora disponibile in fase di esecuzione –