Por que eu devo ler este artigo:Através de exemplos comparativos entre as versões do Delphi, é mostrado como o recurso de Live Bindings amadureceu. Os exemplos mostram como a praticidade se tornou o foco em sua utilização, colocando lado a lado situações que sofreram melhoras, por exemplo, a notificação de mudanças nos bindings, o surgimento de um assistente para criação de Bindings, binding de objetos não visuais e outras.

O LiveBindings foi lançado juntamente com o FireMonkey no Delphi XE2, principalmente porque esta nova plataforma de desenvolvimento não contém os controles DataAware tradicionais como existiam na VCL, então optou-se por criar um mecanismo de Binding semelhante ao que já existe na plataforma .NET, o que obviamente uma ótima ideia da Embarcadero. Vale lembrar que este recurso também foi disponibilizado para os componentes da VCL.

Já era previsto que houvesse melhorias no LiveBindings para as novas versões do Delphi, já que o recurso surgiu no Delphi XE2, onde ainda era um tanto trabalhoso de usar. Em sua primeira versão, as notificações de atualização entre os controles eram feitas manualmente via código.

Já nas versões mais recentes do IDE, estas notificações são automáticas, bastando o desenvolvedor ligar os controles de forma gráfica e intuitiva.

Foram criados dois facilitadores para esta tarefa que são o LiveBindings Designer e o LiveBindings Wizard.

FireMonkey

O FireMonkey é o novo Framework de desenvolvimento de aplicações criado pela Embarcadero a partir do Delphi XE2. Seu propósito surgiu através da necessidade de criar aplicações com visual mais rico e que sejam multiplataforma. Os recursos gráficos do FireMonkey fazem uso da GPU do hardware, possibilitando o trabalho com aplicações HD, 3D.

A versão FireMonkey 2 presente no Delphi XE3 trouxe algumas novidades como Actions, Anchors, Touch e Gesture, recursos estes que já existiam na VCL.

DataBinding

O DataBinding é uma técnica de ligação entre duas fontes de dados que nos permite manter a sincronização destes, onde uma alteração feita por um elemento reflete automaticamente nos elementos ligados a ele. Para isto temos um objeto de origem (source) e um ou mais objetos de destino (target). Alterações no objeto de origem irão refletir automaticamente nos objetos de destino.

O uso mais comum de DataBinding é o de ligar campos do banco de dados ou atributos de uma classe a um controle de tela, como Edits, Memos, Grids, etc.

Podemos ter três tipos de ligações entre estes elementos:

  • OneWay: onde somente o objeto de origem atualiza o de destino;
  • TwoWay: neste os dois fazem atualizações no outro;
  • OneWayToSource: aqui o destino quem faz atualizações no objeto de origem.

LiveBindings

O LiveBinding é um mecanismo de DataBinding que foi incorporado na versão XE2 do Delphi e que tem o objetivo de fazer a ligação de fontes distintas de dados através de expressões. Estas expressões são relacionais, conhecidas como Binding Expressions, podendo ser unidirecional ou bidirecional, que define o sentido do fluxo de dados na ligação.

  • Unidirecional: a alteração é feita apenas na origem, ou seja, a propriedade de destino apenas reflete os dados da origem.
  • Bidirecional: a alteração é feita na origem e no destino, ou seja, qualquer alteração é refletida tanto na origem quanto no destino.
  • Por meio destas expressões podemos ter qualquer objeto ligando com qualquer outro, simplesmente criando esta expressão de ligação entre eles.

No LiveBinding temos os objetos que são os Source Objects (objetos de origem) e os Control Objects (objetos de controle). Há a possibilidade de um mesmo objeto ser tanto de origem quanto de controle. Os componentes disponíveis podem ser vistos na Figura 1.

Componentes LiveBindings no
Delphi XE4
Figura 1. Componentes LiveBindings no Delphi XE4.

LiveBindings Designer

Este editor pode ser visualizado usando o menu View/LiveBindings Designer, ele nos exibe os componentes que temos em nossa tela e a partir de agora podemos fazer a ligações deste componentes simplesmente traçando uma linha simples entre as propriedades dos objetos.

A partir desta versão, o próprio Delphi se encarrega de disparar as notificações entre os componentes, não precisamos mais programar nenhum método nem codificar nenhum evento para esta tarefa, como tínhamos anteriormente no Delphi XE2.

A seguir uma breve descrição de cada botão do editor conforme a ordem da Figura 2.

  • Fit in Window: redimensiona os itens para se adequar ao tamanho atual do editor;
  • Zoom In: aumenta o tamanho dos itens do editor;
  • Zoom Out: diminui o tamanho dos itens do editor;
  • Restore Actual Size: restaura o tamanho padrão dos itens;
  • LiveBindings Wizard: abre um wizard que ajuda na criação de Bindings.
Botões do Editor
Figura 2. Botões do Editor.

No Editor de Bindings também temos os chamados Layers ou camadas, que são diferentes formas de visualização que podemos ter das ligações entre os componentes, como pode ser visto na Figura 3.

A ideia é dar foco a alguns componentes e ligações que desejamos. Isto é muito útil quando há muitas ligações dentro do formulário, como por exemplo dois ClientDataSets ligado a vários controles. Neste caso poderíamos ter duas visualizações, uma para cada ClientDataSet.

Layers do
Wizard
Figura 3. Layers(camadas) do Wizard.

Existem alguns componentes, como rótulos, que não temos a necessidade de termos no nosso editor de Bindings e que acabam poluindo a tela.

Podemos deixar invisíveis estes controles para o editor, bastando apenas acionarmos o botão direito dentro do editor e escolher a opção “Show/Hide elements...”. Será aberta uma janela com todos os itens do formulário, onde basta desmarcar os controles que não desejamos que sejam exibidos no editor, conforme a Figura 4.

cultando elementos
do editor
Figura 4. Ocultando elementos do editor.

Olhando para o editor vemos que as principais propriedades de cada componente ficam disponíveis para fazermos a ligação, porém, podemos adicionar as propriedades que estão ocultas de cada componente, basta clicarmos nos “três pontos” no canto inferior direito de cada componente do editor que ele vai trazer todas as propriedades disponíveis naquele componente, e então podemos escolher quais desejamos que estejam disponíveis no editor, conforme a Figura 5.

Propriedades ativas
ou inativas no Editor
Figura 5. Propriedades ativas ou inativas no Editor.

Acionando o botão direito dentro do editor, temos outro interessante recurso, que é o de exportar nosso diagrama como imagem, conforme mostra a Figura 6. Podemos configurar várias opções relacionadas ao tamanho do diagrama.

Temos um preview do resultado e podemos salvar em vários formatos de imagens. Isso é interessante para documentação da aplicação que estamos desenvolvendo.

Exportando diagrama
para imagem
Figura 6. Exportando diagrama para imagem.

Notificações no Delphi XE2

Na versão XE2 do Delphi, para refletirmos o texto de um Edit no Caption de um Button tínhamos que fazer as seguintes operações. Ir na propriedade LiveBindings e escolher New LiveBinding.

Após escolher a opção TBindExpression, era criado o componente TBindingsList onde deveríamos configurar na nossa expressão as seguintes opções:

  • Control Expression: propriedade do Button afetada, no caso Text.
  • Source Component: componente de origem, no caso o Edit.
  • Source Expression: expressão, que pode ser simplesmente Text ou qualquer função adicional.

Para o correto funcionamento do exemplo ainda precisava-se implementar um procedimento de notificação na seção published da unit, para que a cada troca de dados no Edit os controles ligados sejam notificados, conforme a Listagem 1.

Listagem 1. Evento de notificação.


  01 procedure Notify(Sender: TObject);
  02 begin
  03   BindingsList1.Notify(Sender, "");
  04 end;

Finalmente, no evento OnChange do Edit devíamos vincular a procedure Notify e ao executar tudo funcionava conforme o planejado.

Note que para apenas uma relação tivemos uma série de configurações a fazer além da codificação, que não deveria ser necessária, já que isso faz parte do recurso de LiveBindings e não é uma lógica de nossa aplicação. Veremos a seguir o quanto isso ficou fácil nas versões recentes do IDE.

Notificações no Delphi XE4

Para termos o mesmo exemplo no Delphi XE4 basta segurarmos o botão esquerdo do mouse da propriedade Text do Edit até a propriedade Text do Button. Pronto, basta executarmos a aplicação e temos o nosso exemplo em funcionamento, conforme a Figura 7.

Ligação visual dos componentes
Figura 7. Ligação visual dos componentes.

É claro que para o tratamento avançado desta ligação temos que ir na expressão do componente TBindingsList, mas sem dúvida este Wizard nos traz muita produtividade no desenvolvimentos de telas com vários controles interligados.

LiveBindings Wizard

Temos disponíveis a partir do Delphi XE3 também o LiveBindings Wizard, onde é possível acessá-lo acionando o botão direito do mouse em qualquer componente da tela e escolher a opção referida.

Será aberta uma tela para ajudar o desenvolvedor a criar a ligação entre os objetos. Essa Wizard facilita muito o desenvolvedor a criar as ligações. Vale lembrar que este é muito sensível ao contexto, portanto, dependendo do componente selecionado, mudam as opções disponíveis no Wizard.

Esse Wizard é dividido em duas partes, no lado esquerdo ficam os passos envolvidos no assistente e no lado direito as opções disponíveis ao desenvolvedor naquele momento.

Temos várias opções de ligações no assistente, como as seguintes:

  • Ligar um controle a um campo Field;
  • Ligar um grid a um DataSource;
  • Ligar a propriedade de um componente à propriedade de outro componente;

Nota: Para acessarmos o Wizard do LiveBindings no Delphi XE3 pelo botão direito do mouse devemos mudar uma configuração do IDE, pois este recurso não vem habilitado por padrão. Para habilitá-lo basta acessar Tools>Options>LiveBindings e marcar a opção “Display LiveBindings Wizard in rigth-click menu”.

LiveBindings, ClientDataSet e Action Lists

O componente TActionList foi disponibilizado no FireMonkey a partir da versão XE3 e junto a ele vieram algumas Actions padrões do LiveBindings, conforme podemos notar na Figura 8. Estas ações são semelhantes aquelas que encontramos no componente TBindNavigator e estão relacionadas às funções do ClientDataSet.

Actions relacionadas à
LiveBindings disponíveis
Figura 8. Actions relacionadas à LiveBindings disponíveis.

Agora vejamos a facilidade de utilização dos componentes do FireMonkey em conjunto com o LiveBindings e que são necessárias muito poucas linhas de código para fazer a ligação entre os componentes.

Primeiro criamos um novo projeto FireMonkey e adicionamos o componente TClientDataSet, ligando o mesmo a qualquer origem de dados (XML, CDS, SqlDataSet, etc), em seguida, adiciona-se o componente TGrid na tela, acionando sobre ele o botão direito do mouse>LiveBindings Wizard.

Então temos a nova janela de Wizard e a opção de conectar o Grid a um DataSource. Na guia seguinte optamos por fazer o link ao componente ClientDataSet adicionado anteriormente. Podemos ainda adicionar um DataSourceNavigator e finalizar o Wizard.

Visualizando o formulário há agora novos componentes. O TBindNavigator para navegar/incluir/alterar/excluir registros, note também que foi criado um TBindDataSource que tem uma função muito semelhante ao DataSource presente na VCL, inclusive ele possui internamente um DataSource e um DataSet para fazer essa junção.

Outro componente gerado é o TBindingList que é o componente que liga a nossa grade de dados ao BindSourceDB. Ele cria internamente o objeto TLinkGridToDataSource onde fica armazenado o grid de dados e o DataSource de origem das informações. Através da propriedade Columns podemos ainda definir quais colunas queremos que sejam exibidas.

Agora adicione um TActionList e uma ação TFMXBindNavigateNext através do Action List Editor e aponte a propriedade DataSource para o nosso BindDataSource já presente na tela. Para finalizar atribuímos a propriedade Action do botão na ação que acabou de ser criada. Executamos a aplicação e vemos que não foi necessária nenhuma linha de código para fazer toda essa combinação. Podemos usar o botão Next para avançarmos no grid. Desta mesma forma poderíamos ter usado qualquer outra operação do ClientDataSet, como Insert, Edit, Delete e etc.

É possível ainda adicionar um Edit e um Label vinculado ao campo Description. Basta acionarmos o LiveBindings Wizard pelo ClientDataSet, escolhermos a opção “Link a field to ClientDataSet to a control”, escolher o campo Description e em seguida selecionar o controle que desejamos, no caso TEdit. No último passo marcamos a opção para adicionar um Label. O resultado é o mostrado na Figura 9.

Componentes para ligação do
Grid
Figura 9. Componentes para ligação do Grid.

Observe agora que foi criada mais uma expressão no nosso TBindingsList, o tipo é TLinkControlToField (Figura 10) e como o nome diz serve para ligarmos um controle de tela a um TField do ClientDataSet.

Expressão de ligação entre
TField e Control
Figura 10. Expressão de ligação entre TField e Control

Criação de Protótipos

Na versão XE3 do Delphi também tivemos a adição de um novo componente chamado TPrototypeBindSource. Sua função é criar protótipos de base de dados para testes. Agora não somos mais obrigados a criarmos um banco de dados para testar nossa aplicação, nem ligarmos um ClientDataSet a um XML, basta utilizarmos este componente. É extremamente útil para criarmos aplicações de modelo.

Para usá-lo, basta clicar duas vezes e acionar Add New. Será apresentada uma janela conforme a Figura 11 onde informamos o nome do campo e tipo do campo. Veja que ele é semelhante à configuração dos TFields do ClientDataSet, porém, não é persistido em nenhum lugar.

Cada um dos campos adicionados pode estar ligado a um Generator que tem a função de gerar dados de teste para o campo, facilitando bastante o desenvolvimento de protótipos a aplicativos de demonstração.

Adicionando campos
no Protótipo
Figura 11. Adicionando campos no Protótipo.

Agora podemos adicionar Grids, Edits, Labels e através do LiveBinding Wizard, vincularmos aos campos, conforme podemos observar na Figura 12.

Demonstração do
protótipo final
Figura 12. Demonstração do protótipo final.

Criando nosso próprio Generator

Podemos desenvolver nosso próprio gerador de dados. Nesse caso simularemos um gerador de IDs em sequência. Para isso, devemos criar um novo pacote para o gerador, além disso, implementaremos uma classe chamada TIDsGenerator que herdará da classe TDelegateValueGenerator, classe base para todos os geradores e que possui um método virtual CreateDelegate que precisamos sobrescrever para implementarmos o gerador personalizado. O código da classe é exibido na Listagem 2.

Listagem 2. Classe TIdsGenerator01 unit uIDsGenerator;


  02 
  03 interface
  04 
  05 uses
  06   Data.Bind.ObjectScope, System.Generics.Collections;
  07 
  08 type
  09   TIdsGenerator = class(TDelegateValueGenerator)
  10   protected
  11     function CreateDelegate: TValueGeneratorDelegate; override;
  12   end;
  13 
  14 implementation
  15 
  16 { TDataGenerator }
  17 
  18 function TIdsGenerator.CreateDelegate: TValueGeneratorDelegate;
  19 var
  20   ListaIds: TList<Integer>;
  21   i: Integer;
  22 begin
  23   ListaIds := TList<Integer>.Create;
  24   try
  25     for i := 0 to 50 do
  26       ListaIds.Add(i);
  27     Result := TTypedListValueGeneratorDelegate<Integer>.Create(
                     Options, ListaIds.ToArray);
  28   finally
  29     ListaIds.Free;
  30   end;
  31 end;
   32 initialization
  33   RegisterValueGenerator("Gerador IDs", [ftInteger],
  34     TValueGeneratorDescription.Create(TIdsGenerator, "", 
            "uIDsGenerator"));
  35 finalization
  36   UnRegisterValueGenerator("Gerador IDs", [ftInteger], "");
  37 end.

Para retornarmos os dados usamos a classe TTypedListValueGeneratorDelegate (linha 27) que através de Generics pode receber qualquer classe. Observe que o segundo parâmetro é um TArray de Integer, porque definimos que o tipo retornado seria Integer. Se tivéssemos informado String antes de chamar o construtor Create, seria retornado um Array de Strings, se passado um Double seria retornado um Array de Doubles e assim por diante.

Aqui podemos perceber os Generics sendo utilizados para resolver este problema da compatibilidade de tipos (Type Casting), ou seja, pode-se criar uma lista de qualquer classe ou tipo primitivo para retornarmos.

Esta classe deve ser incluída em um pacote e, após compila-lo, deve-se realizar sua instalação no IDE para que ele apareça na lista de geradores do componente TPrototypeBindSource, conforme Figura 13.

Gerador de IDs
Figura 13. Gerador de IDs.

Na Figura 14 foi adicionado a um formulário um componente grid e vinculado ao gerador com os IDs. Sua ligação foi feita pelo gerador ContactName, padrão do Delphi.

Gerador em execução
Figura 14. Gerador em execução.

Investindo um tempo para criação de geradores personalizados fica muito mais fácil a criação de protótipos de aplicação. Poderíamos gerar Datas de Nascimentos aleatórias, e-mails, CPFs, existem muitos dados de testes que os desenvolvedores utilizam no dia a dia.

Seria interessante ainda termos um pacote com todos os nossos geradores personalizados e podermos utilizar em qualquer aplicação que criemos, lembrando que podemos usar este recurso tanto em aplicações VCL quanto FireMonkey, o que torna isso ainda mais vantajoso.

Componente TBindingsList

Este componente é o grande responsável por fazer a ligação entre dois objetos. É nele que fica a expressão de ligação. Se colocarmos um Edit e um Button e realizarmos uma ligação através do Editor das propriedades Text dos dois componentes, automaticamente será adicionado um componente do tipo TBindingsList com um item internamente, conforme mostra a Figura 15.

Propriedades do TBindingsList
Figura 15. Propriedades do TBindingsList.

As propriedades mais interessantes de analisarmos neste componente são a lista de métodos e formas de conversão de dados, através das propriedades Methods e OutputConverters que nos mostram quais são os métodos e conversões de dados que podemos usar nas propriedades dos objetos que ligamos.

Se atentarmos aos itens do TBindingsList, veremos que foi criado um link entre os dois componentes. Deste modo, podemos olhar com atenção suas propriedades e entendermos como funciona o mecanismo de Binding do Delphi, conforme mostrado na Figura 16 e na Tabela 1, respectivamente.

Propriedades do
Link criado
Figura 16. Propriedades do Link criado.
Propriedades dos componentes Link
Tabela 1. Propriedades dos componentes Link.

Observe que aqui vimos somente um tipo de Binding que é o TLinkControlToProperty, mas existem muitos outros, como pode ser visto na Figura 17. Cada um tem uma função específica e que se encaixa em determinadas situações. Devemos evitar o uso dos DB Links, pois foram marcados como obsoletos e só permanecem por questão de retro compatibilidade.

Tipos de Bindings
disponíveis
Figura 17. Tipos de Bindings disponíveis.

Um evento importante contido em todas as expressões é o OnEvalError. Esta recebe como parâmetro um objeto do tipo Exception e intercepta qualquer tipo de exceção ocorrida em nossa expressão, exibindo-a de forma familiar ao usuário, como na Listagem 3.

Listagem 3. Manipulando Exceções nas expressões.


  01 procedure TForm1.LinkControlToPropertyTextEvalError(Sender: TObject;
       AException: Exception);
  02 begin
  03   raise Exception.Create("Classe do Erro: " + AException.ClassName + 
         #13#10 + "Mensagem: " + AException.Message);
  04 end; 

Ligando componentes não visuais no Delphi XE2

Neste exemplo veremos como tínhamos que fazer a ligação entre objetos de negócio e componentes visuais no Delphi XE2. A ideia é ligar um simples TEdit a uma propriedade de uma classe não visual.

A interface é muito simples e pode ser visualizada na Figura 18. O código pode ser visualizado na Listagem 4.

Interface do
exemplo
Figura 18. Interface do exemplo.

Listagem 4. Código completo da Unit.


  01 unit ufrMain;
   
  02 interface
   
  03 uses
  04   FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Edit, 
         System.Classes,
  05   System.Bindings.Expression, System.Bindings.Helper;
   
  06 type
  07   TPessoa = class
  08   strict private
  09     FNome: string;
  10   public
  11     property Nome: string read FNome write FNome;
  12   end;
   
  13   TfrmMain = class(TForm)
  14     Edit1: TEdit;
  15     Button1: TButton;
  16     procedure btnExibirClick(Sender: TObject);
  17     procedure FormDestroy(Sender: TObject);
  18     procedure edtNomeChange(Sender: TObject);
  19     procedure FormCreate(Sender: TObject);
  20   private
  21     FPessoa: TPessoa;
  22   public
  23   end;
   
  24 var
  25   frmMain: TfrmMain;
  26   BindingExpression: TBindingExpression;
   
  27 implementation
  28 {$R *.fmx}
   
  29 procedure TfrmMain.FormCreate(Sender: TObject);
  30 begin
  31   FPessoa := TPessoa.Create;
  32   BindingExpression := TBindings.CreateManagedBinding(
  33     [TBindings.CreateAssociationScope([Associate(Edit1, "Edit")])],
  34     "Edit.Text",
  35     [TBindings.CreateAssociationScope([Associate(FPessoa, "Pessoa")])],
  36     "Pessoa.Nome", nil);
  37 end;
   
  38 procedure TfrmMain.edtNomeChange(Sender: TObject);
  39 begin
  40   TBindings.Notify(Sender, "Text");
  41 end;
   
  42 procedure TfrmMain.btnExibirClick(Sender: TObject);
  43 begin
  44   ShowMessage(FPessoa.Nome);
  45 end;
   
  46 procedure TfrmMain.FormDestroy(Sender: TObject);
  47 begin
  48   FPessoa.Free;
  49 end;
   
  50 end.

Na linha 5 temos a declaração das duas units necessárias para podermos implementar este exemplo. Criamos a classe TPessoa com uma única propriedade: “Nome”, optou-se por criar na mesma unit do formulário para facilitar (linhas 06 a 12).

Na linha 26 é definida uma variável de escopo global do tipo TBindingExpression, esta será responsável por armazenar a expressão que realizará a ligação dos dados.

Entre as linhas 29 a 37 há a codificação do evento OnCreate do formulário. Primeiramente é instanciada a classe TPessoa (linha 31). Na linha 32 é realizado o mecanismo de Binding entre TPessoa.Nome e Edit.Text.

Para realizar essa associação, é utilizado o método CreateManagedBinding da classe TBindings. O primeiro parâmetro é um array de objetos de Origem dos dados. Já o segundo é a expressão de ligação que será utilizada para fazer o Binding.

O terceiro parâmetro é um Array de objetos de destino, que receberá os dados do LiveBinding, já o quarto parâmetro é a expressão que será utilizada para armazenar o valor de saída.

A função Associate serve para vincularmos um objeto a uma String, já que o LiveBinding não trabalha diretamente com os objetos e sim com expressões, por isso a necessidade desta associação.

Somente com esta ligação feita no evento OnCreate nosso exemplo ainda não funcionaria. Isso porque na versão anterior do Delphi não havia o recurso de auto notificação, ou seja, o framework não gerenciava os objetos relacionados para a atualização automática. Precisamos então notificar manualmente, ou seja, devemos codificar o evento OnChange do Edit e notificar o componente da mudança (linha 40).

No evento OnClick do botão simplesmente é exibido o conteúdo da propriedade Nome do objeto FPessoa. No evento OnDestroy objeto FPessoa é liberado da memória.

Como se percebe neste exemplo tudo funcionou, no entanto, tivemos bastante trabalho para fazer as ligações entre os componentes visuais e os objetos. Isso melhorou muito nas novas versões do Delphi como veremos a seguir.

Ligando componentes não visuais no Delphi XE3 e XE4

A partir do Delphi XE3 foram adicionados novos recursos que vieram nos trazer facilidades para trabalhar com Bindings de componentes não visuais.

Primeiramente, vamos criar um novo projeto FireMonkey, e em seguida, implementar uma nova classe chamada TContato, conforme ilustra a Listagem 5. É uma classe muito simples que dispõe de um construtor personalizado para facilitar a população dos Fields.

Listagem 5. Classe TFuncionario.


  01 unit uContato;
   
  02 interface
   
  03 type
  04   TContato = class
  05   private
  06     FNome: string;
  07     FIdade: Integer;
  08     FEmail: string;
  09   public
  10     constructor Create(Nome: string; Idade: Integer; Salario: Double);
  11     property Nome: string read FNome write FNome;
  12     property Idade: Integer read FIdade write FIdade;
  13     property Email: string read FEmail write FEmail;
  14   end;
   
  15 implementation
   
  16 constructor TFuncionario.Create(Nome: string; Idade: Integer; Email:  
       string);
  17 begin
  18   FNome := Nome;
  19   FIdade := Idade;
  20   FEmail := Email;
  21 end;
   
  22 end.

Como nota-se, o código da Listagem 5 é simples. Entre as linhas 11 e 13 definimos as propriedades públicas da nossa classe TContato. Observe que na linha 10 foi definido o construtor. Este foi implementado a partir da linha 16, fazendo com que os atributos da classe recebam os valores diretamente em sua criação.

Finalizada a implementação, o próximo passo é definir os campos da classe anteriormente criada, no componente TDataGeneratorAdapter, através da propriedade FieldDefs. Basta adicioná-los de acordo com o tipo desejado (Figura 19).

Criando os Fields de acordo com
a Classe
Figura 19. Criando os Fields de acordo com a Classe

Agora adicionamos o componente TAdapterBindSource e ligamos nele o TDataGeneratorAdapter através da propriedade Adapter. Em seguida ligamos nossos controles de tela (edits) ao nosso Adapter.

Para finalizar a ligação entre nossa classe e o componente TAdapterBindSource, no evento OnCreateAdapter escrevemos o código da Listagem 6.

Listagem 6. Evento OnCreateAdapter Objeto.


  01 procedure TForm2.AdapterBindSource1CreateAdapter(Sender: TObject;
  02   var ABindSourceAdapter: TBindSourceAdapter);
  03 begin
  04   FContato := TContato.Create("Filipe", 25, 
         "filipe.dalepiane@gmail.com");
  05   ABindSourceAdapter := TObjectBindSourceAdapter<TContato>.Create
       (Self, FContato);
  06 end;

Na linha 4 simplesmente é instanciado o objeto da classe TContato atribuindo seus Fields. Na linha 5 usamos a variável ABindSourceAdapter (do parâmetro) e define-se o vínculo entre o TAdapterBindSource e a classe TContato através da nova instância de TObjectBindSourceAdapter. Observe que é usado Generics (ver BOX 2) para dizer qual o tipo (TContato) e o objeto (FContato) que deve ser usado para fazer a inicialização. Esta classe pode ser usada para fazer vínculo de qualquer objeto a qualquer TAdapterBindSource.

Generics

Generics é um recurso presente desde o Delphi 2009 que permite a criação de estruturas ge

néricas. Pode-se definir o tipo de uma lista de objetos que serão adicionados. Se o objeto adicionado não for o especificado, teremos um erro ainda em tempo de compilação, evitando assim erros de TypeCasting que ocorriam em versões anteriores do Delphi.

Você pode estar se perguntando no momento, e se eu quiser um grid com uma lista de objetos de TContato, sem problemas, basta adicionar outro TAdapterBindSource a através do próprio Wizard, ligá-lo com o componente Grid.

Em seguida, basta configurar novamente o evento OnCreateAdapter como sugere a Listagem 7.

Listagem 7. Evento OnCreateAdapter Lista.


  01 procedure TForm2.AdapterBindSource2CreateAdapter(Sender: TObject;
    var ABindSourceAdapter: TBindSourceAdapter);
  02 begin
  03   FListaContatos := TObjectList<TContato>.Create;
  04   FListaContatos.Add(TContato.Create("Filipe", 25, filipe@gmail.com"));
  05   FListaContatos.Add(TContato.Create("Cíntia", 27, "cintia@gmail.com"));
  06   FListaContatos.Add(TContato.Create("Julio", 32, "julio@gmail.com"));
  07   ABindSourceAdapter := TListBindSourceAdapter<TContato>.Create(Self, 
          FListaContatos);
  08 end; 

Observe que a única diferença entre as duas listagens é que na primeira é passado um único objeto, enquanto na segunda, cria-se uma lista de objetos de TContato através da classe TObjectList, presente na unit Generics.Collections.

O diagrama da Figura 20 mostra como ficaram as ligações finais da aplicação.

Diagrama final de ligações
entre os componentes do formulário
Figura 20. Diagrama final de ligações entre os componentes do formulário.

Ao executar a aplicação, é possível verificar o funcionamento tanto de um objeto quanto de uma lista de objetos. A Figura 21 ilustra o resultado final.

Aplicação em funcionamento
Figura 21. Aplicação em funcionamento.

Novo componente TParamsAdapter do Delphi XE4

A mais nova versão do Delphi trouxe consigo um novo componente na paleta LiveBindings, o TParamsAdapter. Este componente surgiu para podermos ligar componentes de acesso a dados do DBExpress ao componente TAdapterBindSource.

Como já abordado, o TAdapterBindSource foi criado para realizar o Binding de qualquer fonte de dados através de um Adapter.

Anteriormente, na ligação de classes utilizamos o TDataGeneratorAdapter para definir o Binding, já no TParamsAdapter pode-se vincular qualquer SQLDataSet, SQLQuery, SQLServerMethod e/ou SQLStoreProc.

Após isso, basta liga-lo ao TAdapterBindSource através da propriedade Adapter e trabalhar normalmente, manipulando o evento OnCreate como feito anteriormente.

Como vimos, há vários tipos de Binding que podem ser usados em nossas aplicações, ligações em componentes, componentes em DataSets, componentes a Objetos e muitos outros tipos. Pode-se ainda estender o framework de modo a implementar o padrão MVC por exemplo.

O FireMonkey veio para ficar e se quisermos que nossas aplicações tenham interfaces ricas e multiplataforma, devemos dominar o recurso de LiveBinding para desenvolvermos aplicações de qualidade, seguras e ágeis.

Confira também


Links
  • Data Binding Overview:
    Data binding is the process that establishes a connection between the application UI and business logic.

Saiba mais sobre Delphi ;)

  • Guias de Estudo Delphi:
    Aqui você encontra os Guias de estudo da linguagem Delphi. Descubra como dominar o Delphi, desde o recurso mais básico ao mais avançado. Escolha o seu!