0item(s)

Vous n'avez aucun produit dans votre panier

Product was successfully added to your shopping cart.
Swipe to the left

LiveBindings par Didier Cabalé - MVP Embarcadero

By Maxime Capellot 20 décembre 2016 442 Views No comments

Didier Cabalé - MVP Embarcadero

LiveBindings avec TObject ou TObjectList

Dès ses début, Delphi a voulu se positionner en tant qu'outil RAD (Rapid Application Development)

La philosophie du RAD était de pouvoir dessiner l'application avec des composants et des contrôles visuels, en définissant leurs propriétés (via l'inspecteur d'objet), et en essayant d'avoir à coder *le moins possible*. Le dynamisme est assuré par le couplage fort entre l'UI et la source de donnée. Ex: lorsque je scrolle dans mon dataset, la donnée représentée par mon contrôle se met à jour automatiquement.

Dans ce cadre là, Delphi mettait à disposition du développeur des contrôles "sensibles aux donnés" (data aware): quand on voulait relier un TEdit, ou un TComboBox, ou un TStringGrid à une source de donnée, on utilisait alors, toujours pour rester dans cet esprit RAD, des TDBEdit, TDBCombobox, TDBGrid.

"So far, so good", comme on dit. Le problème est qu'en voulant faciliter le développement, on le contraint à des "solutions prêtes à l'emploi": le TDBxyx est forcément un contrôle du genre Txyz, mais relié à une source de donnée. Et si je voulais relier mon Txyz à autre chose qu'à une source de donnée, à un autre composant, ou à un autre objet par exemple, je ne le pourrais pas aisément.

Pour résoudre ce problème, les concepteurs de Delphi décidèrent de créer LiveBindings:

LiveBindings est un framework permettant de séparer clairement l'interface utilisateur de la logique métier, de rendre le contrôle visuel (TEdit, TCombobox, TStringGrid) indépendant de la source à laquelle il peut être liée.

L'objet de cet article est donc de montrer comment lier un contrôle visuel (TEdit, TStringGrid) à un Objet (descendant d'un TObject)

1. En conception, liaison du contrôle visuel avec un TPrototypeBindSource

L'objet du TPrototypeBindSource est de créer une source de donnée virtuelle, censée représenter le TObject que nous voulons utiliser par la suite, dont nous pourrons définir le comportement vis à vis du composant auquel il sera lié.

Depuis notre "Form Designer":

1. Ajoutons un TPrototypeBindSource. Depuis son inspecteur d'object et sa propriété FieldDefs (TGeneratorFieldDefs), ajoutons un TGeneratorFieldDef -> TGeneratorFieldDefs[0]. A ce TGeneratorFieldDefs[0] nouvellement créé, spécifions la valeur 'FField1' à sa propriété [Name].

Notez que la valeur de cette propriété, FField1, sera le nom d'un champ du TObject, qui remplacera le TPrototypeBindSource.

2. Ajoutons le contrôle auquel sera lié notre TObject, un TEdit.

Maintenant, concentrons nous sur la liaison TPrototypeBindSource <-> TEdit:

Afin d'obtenir une représentation plus claire, nous dessinerons les liaisons que nous aurons décidé pour notre contrôle visuel, en utilisant les graphes de liaison du "LiveBindings Designer"

Depuis le [LiveBindings Designer]:

Les composants et leurs propriétés utilisés ici seront:

Edit1 (TEdit) /propriété: Text

PrototypeBindSource1 (TPrototypeBindSource) /propriétés: FieldDefs, collection de TGeneratorFieldDef

BindingsList1 (TBindingsList): ce composant n'est qu'un conteneur de 'Binding', affichables en double-cliquant dessus. Les actions réalisées dans le LiveBindings designer, ont créé pour nous un "contrôle de liaison", adapté au type de liaison que nous avons choisi (lien bi-directionnel entre la propriété d'un contrôle (Text) et un champ de notre TPrototypeBindSource (FField1)). Le "contrôle de liaison" contenu, LinkControlToField1, est du type TLinkControlToField.

LinkControlToField1 (TLinkControlToField) /propriétés: Control: Edit1; DataSource: PrototypeBindSource; FieldName: FField1; Direction: linkBidirectional

** Note **

Vous aurez peut-être remarqué qu'à aucun moment du processus de développement via LiveBindings, il n'a été question de faire référence à la propriété [Text] de Edit1, pourtant un des deux points de liaison. La raison en est que le "contrôle de liaison" utilisé, le TLinkControlToField est de la catégorie "Quick Bindings", et qu'à ce titre, le membre enregistré comme "observable" sera mis en avant dans le "LiveBindings designer".

ex: pour un TEdit, le membre "observable" enregistré est sa propriété "Text".

** Important **

Vous noterez que le Edit1 n'a aucune connaissance du composant avec lequel nous voulons le lier, PrototypeBindSource1. De la même façon, PrototypeBindSource1 n'a aucune connaissance du contrôle avec on veut le lier (Edit1)

Ceci est primordial, car celà montre que l'on sépare clairement les sujets: d'un côté l'interface utilisateur, représenté par Edit1; de l'autre la logique métier, représenté par PrototypeBindSource1.

Ce qui fera la liaison entre les deux est le contrôle de liaison, de type TLinkControlToField.

2. Déclaration et instanciation de notre objet

Pour les besoins de l'exemple, imaginons un objet simple de type TMyObject, déclaré et instancié comme suit:


type
  TMyObject = class(TObject)
  private
    FField1: string;
  public
    constructor Create(aField: string);
    property Field1: string read FField1;
  end;

...

constructor TMyObject.Create(aField: string);
begin
  FField1 := aField;
end;


3. Passage du "modèle" au "réel":

Si nous avons utilisé jusqu'ici utilisé un TPrototypeBindSource, c'est parce que nous ne pouvions pas réaliser cette modélisation avec un TObject.

Il s'agit maintenant de remplacer le TPrototypeBindSource par notre TObject, et cette action interviendra au moment de l'initialisation du TPrototypeBindSource, lors de l'événement [onCreateAdapter]

** Note **

Comme cet événement survient avant l'événement [OnCreate] de Form1, nous serons obligés de créer l'objet à ce moment là.


procedure TForm4.PrototypeBindSource1CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  FMyObject := TMyObject.Create('value for Field1');
  ABindSourceAdapter := TObjectBindSourceAdapter<TMyObject>.Create(self, FMyObject, false);
end;


C'est prêt. Exécutez et voyez le résultat:

4. Allons plus loin, avec une liaison TStringGrid <-> TObjectList<TMyObject>

4.1. Conception via "Visual LiveBindings"

La liste des champs de TMyObject peut ne pas être connue à l'avance. Dans ce cas, nous lierons les deux composants StringGrid1 <-> PrototypeBindSource2, par tous leurs champ (marqué par une étoile dans le "LiveBindings Designer")

Les composants et leurs propriétés utilisés ici seront:

StringGrid (TStringGrid) /propriétés: aucune propriété à spécifier en particulier

PrototypeBindSource2 (TPrototypeBindSource) /propriétés: aucune propriété à spécifier en particulier

BindingsList1 (TBindingsList): ce composant n'est qu'un conteneur de 'Binding', affichables en double-cliquant dessus. Les actions réalisées dans le LiveBindings designer, ont créé pour nous un "contrôle de liaison", adapté au type de liaison que nous avons choisi (lien bi-directionnel entre les cellules d'un TStringGrid et tous les champs de notre TPrototypeBindSource). Le "contrôle de liaison" contenu, LinkControlToField1, est du type TLinkGridToDataSource.

LinkGridToDataSourcePrototypeBindSource2 (TLinkGridToDataSource) /propriétés: GridControl: StringGrid1; DataSource: PrototypeBindSource2

4.2. Déclaration et instanciation de nos objets, TMyObject et TObjectList<TMyObject>

Créons une liste d'objets contenant des objets semblables à ceux que nous avons créé en 2., mais à l'intérieur de la méthode TObjectList<TMyObject>.AddRange


procedure CreateList;
  begin
    FMyObjectList := TObjectList<TMyObject>.Create(true);
    FMyObjectList.AddRange([
               TMyObject.Create('value #1'),
               TMyObject.Create('value #2'),
               TMyObject.Create('value #3')
               ]);
  end;

4.3. Passage du "modèle" au "réel":

Remplacement du TPrototypeBindSource par notre TObjectList<TMyObject>, au moment de l'initialisation du TPrototypeBindSource:


procedure TForm4.PrototypeBindSource2CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  CreateList;
  ABindSourceAdapter := TListBindSourceAdapter<TMyObject>.Create(self, FMyObjectList, false);
end;


Vous noterez ici que le paramètre ABindSourceAdapter: TBindSourceAdapter reçoit un autre descendant que celui reçu dans le 3., car il s'agit de spécifier au framework que l'adapteur est maintenant, non pas un objet unique, mais une liste d'objets.

Exécutez et voyez le résultat:


Conclusion:

Nous avons montré ici la liaison de contrôles standards (TEdit, TStringGrid) à un descendant de TObject ou a une liste de ce descendant.

Cette liaison a été réalisée avec le framework LiveBindings.

Cependant, ce framework puissant permet de réaliser beaucoup d'autres choses.

Si vous voulez en savoir plus, visitez ceci -> http://docwiki.embarcadero.com/RADStudio/Berlin/fr...

Vous trouverez les codes sources ici: https://www.barnsten.com/media/LiveBindings_Objects.zip


FireMonkey - Développement d'une application de réalité virtuelle par Paul Toth (MVP Embarcadero)

By Maxime Capellot 12 décembre 2016 1807 Views No comments


Maxime Capellot - Responsable commercial

Avec Paul Toth (MVP Embarcadero), plongez-vous dans la 3D comme jamais auparavant. Découvrez comment programmer une application en réalité virtuelle avec Delphi et un simple téléphone mobile glissé dans une Google Cardboard.