Delphi 2005, ASP.NET e DataGrid

 

O Delphi não é a primeira escolha para os Web developers, no entanto o Delphi 2005 oferece pela primeira vez um ambiente de trabalho que deve ser considerado seriamente ao se começar a escrever códigos para Web. Especialmente para aqueles que têm experiência com o Delphi, a passagem para o mundo ASP.NET pode ser tranqüila e excitante, graças à ajuda do Delphi 2005.

O ASP.NET é a primeira plataforma de web development que permite ao programador do Delphi a possibilidade de usar as ferramentas valiosas que ele reuniu através dos anos - o Paradigma OOP, o luxo dos componentes e a estrutura transparente da lógica de negócios – no mundo da Internet.

Para um programador Delphi experiente, o primeiro contato com esse mundo é muito reconfortante: tudo soa familiar, tudo parece uma etapa mais adiantada do processo de implementação de conceitos, experiência e ideais com as quais ela/ela tenha entrado em contato em algum estágio anterior do desenvolvimento em Delphi.

ClientDataSet, PageProducer, InternetExpress – pode-se citar vários exemplos. Alguém poderia até dizer, 'O pensamento Delphi' conquistou o mundo Web. Embora o Delphi por si só seja raramente mencionado, ele pode ser fonte de orgulho e inspiração para a equipe da Borland e nós, os desenvolvedores Delphi, podemos entrar neste mundo com muita segurança.

O DataGrid é talvez o componente visual mais central do ASP.NET e, desse modo, uma excelente evidência das vantagens desta plataforma. Infelizmente, a documentação sobre como implementá-lo no Delphi é bem escassa e algumas abordagens podem parecer enigmáticas aos iniciantes. Vamos tentar decifrá-las.

Breve introdução

Três linhas de código são suficientes para ativar o DataGrid. É mais ou menos como estamos acostumados a fazer com nosso desktop no mundo Delphi 'normal': inclua o componente no formulário (WebForm), adicione os componentes Data, como SQLConnection (TDatabase), SQLAdapter (TQuery), DataSet (TDataSource), crie a string de conexão, escreva o comando Select  e conecte os componentes no Object Inspector, adicione o código ao evento PageLoad (OnShow) e pressione F9.

 

procedure TWebForm1.Page_Load(sender: System.Object; e:System.EventArgs);

begin

  SQLConnection1.Open;

  SQLDataAdapter1.Fill(DataSet1);

  DataGrid1.DataBind;

end;

DataGrid1.gif 

Figura 1.

Temos a tabela exibida (Grid) no formulário. Não apenas os nomes, como também os objetos e o mundo por trás deles são diferentes do nosso bom e velho Delphi, mas por enquanto as semelhanças irão ajudar-nos a conhecê-los.

DataGrid2.gif 

Figura 2.

O ADO.Net é um ambiente desconectado, muito semelhante ao antigo ClientDataSet. Usamos o DataAdapter para fornecer dados e preencher o DataSet e para conectar a Grid a ele. E isso é tudo. O resultado é bastante rudimentar, mas nossa próxima etapa vai melhorá-lo.

Uma das diferenças importantes do ASP.NET é que nele, o usuário precisa levar em conta o código tanto no arquivo .pas (Unit) como no .aspx. É possível ver isso como um recurso ou apenas como um sinal de que o ASP.NET ainda não está suficientemente maduro (normalmente, não interferimos no conteúdo do arquivo .dfm como texto), mas a interpretação visual ainda não está totalmente automatizada.

Mesmo assim, a divisão dos dois arquivos – o arquivo visual e o código por trás dele – representa um avanço significativo na programação da Internet. Desenvolver um Internet Project no Delphi 2005 é como dançar continuamente entre esses dois lados, o que às vezes demanda até algumas etapas de dança especiais.

Por enquanto, o arquivo .aspx é curto e simples. Clique na propriedade Columns no Object Inspector para abrir o Columns Collection Editor. Existem vários tipos possíveis, por enquanto escolheremos bound columns e daremos a elas as propriedades Datafield e Headertext.

Desativar a propriedade AutoGenerateColumns do DataGrid permite que as colunas sejam personalizadas. No entanto, o acesso ao Object Inspector de todas as colunas está de certa forma 'oculto'. Você só verá o resultado depois de clicar na tag de coluna no arquivo .aspx F11.

O objeto Column oferece várias propriedades visuais para alterar facilmente a cobertura do DataGrid. O Delphi 2005 transforma todos os valores inseridos no Object Inspector aqui em um atributo da tag Object do arquivo .aspx.

DataGrid3.gif 

Figura 3.

Infelizmente, BoundColumn não possui propriedades de ID. Isso significa que não há maneira de acessá-la no código Delphi e de alterá-la no runtime. A não ser que ela seja transferida para Template.

Movendo o DataGrid

O DataGrid ofecere diversos eventos para a manipulação dos dados no Database. Na nova linguagem ASP, eles são denominados comandos: EditCommand, CancelCommand,UpdateCommand, DeleteCommand. Mas o que acionaria esses eventos?

O segredo é adicionar um EditCommandColumn usando o Columns Collection Editor. Esta Column cria links para os eventos. As atualizações não são automáticas, é necessário codificá-las, mas o DataGridCommandEventArgs oferece as informações de como e onde os dados foram alterados:

 

procedure TWebForm1.DataGrid1_UpdateCommand(source: System.Object; e:     System.Web.UI.WebControls.DataGridCommandEventArgs);

var

  dr: DataRow;

begin

   dr := DataSet1.Tables[0].Rows.Find(DataGrid1.DataKeys[e.Item.ItemIndex]);

   //a linha a ser editar

   dr['picture_name']:= Textbox(e.Item.Cells[0].Controls[0] ).text;

   //a primeira coluna visível no DataGrid

   SqlDataAdapter1.Update(DataSet1); //escrever no Database

   DataGrid1.DataSource := DataSet1;

   DataGrid1.DataBind;

end;

 

Nota: O Delphi 2005 não oferece automaticamente o UpdateCommand no DataAdapter. Caso deseje usar o Adapter para atualização, você deve primeiro adicionar o comando e os parâmetros no Object Inspector.

No Edit mode, o DataGrid vai substituir por default os Labels por TextBoxes. E nós ainda podemos ter apenas um controle em uma célula. É por isso que o casting para um TextBox retornará o valor alterado. Podemos interferir por trás dos panos – conforme já mencionado – convertendo as BoundColumns para TemplateColumns.

Isso acontece novamente no Columns editor. Agora, para cada coluna transformada, são criados dois objetos detached que podem ser vistos no arquivo.aspx file: ItemTemplate e EditItemTemplate. O DataGrid usará o primeiro para fazer a renderização. E o segundo para inserir os dados. Os dois novos objetos estão no container da grid - Label e TextBox, mas desta vez eles podem ser acessados em tempo de design através do Object Inspector e acessados em tempo de execução pelo código Delphi.

Clicar na tag do objeto abre a página relevante no Object Inspector. Além da quantidade habitual de propriedades visuais, a mais importante é a ID. Defini-la como um valor exclusivo expõe a integrada no controle web do DataGrid que possa ser acessada do Delphi, por isso o código acima pode agora ser reescrito da seguinte maneira:

 

dr['picture_name']:= Textbox(e.Item.FindControl('PictureName') ).text;

 

Onde 'PictureName' é o ID de Textbox. Não é mais necessário contar a ordem das células e dos controles no DataGrid.

Converter o BoundColumn para TemplateColumn pode alterar, com alguns truques, a aparência total do DataGrid. Por default, o Delphi cria colunas de texto também para os campos Boolean; isso pode ser facilmente alterado. Simplesmente altere 'TextBox' e 'Label' no ItemTemplate relevante por 'CheckBox', e a propriedade 'Text' pela propriedade 'Checked', de modo que o código .aspx ficará assim:

DataGrid4.gif 

Figura 4.

O acesso aos CheckBoxes recém-criados pode ser obtido novamente por meio do ID e da função FindControl. Essa abordagem lhe oferecerá várias possibilidades de 'recompor' e enriquecer o DataGrid. Podemos, por exemplo, adicionar um validador ao EditItemTemplate.

CustomValidator é um web control projetado para examinar os valores do usuário e compara-los às regras de personalização. Vamos observar um exemplo de como atribuir eventos ao 'hidden' nos objetos de container.

Adicionar um CustomValidator ao EditTemplate é bastante objetivo, basta adicioná-lo ao arquivo .aspx:

DataGrid5.gif 

Figura 5.

Crie um evento Validate simples para o Validator:

 

procedure TWebForm1.CustomValidator1_ServerValidate(source: System.Object;

  args: System.Web.UI.WebControls.ServerValidateEventArgs);

begin

  args.IsValid := Length(args.Value )>2;

end;

 

Já sabemos como localizar programaticamente o Validator no evento DataGrid Update:

 

var

  v: CustomValidator;

begin

  v:= CustomValidator(e.Item.FindControl('CustomValidator1'));

 

Mas como atribuir o evento ServerValidate ao controle no container? Bem, seguindo a lógica do Delphi, isso não seria difícil. Estamos acostumados a fazer isso dessa maneira:

 

v.ServerValidate := CustomValidator1_ServerValidate ;

 

Mas no mundo .NET, isso causará um erro:

 

'read/write não é permitido para eventos CLR. Use o procedure Include/Exclude

Eventos(E2298)

 

Multicast não podem ser atribuídos nem lidos a partir de eventos read/write tradicionais do Delphi. Use Include/Exclude para adicionar ou remover métodos'. Portanto, vamos reformular a instrução:

 

Include(v.ServerValidate, CustomValidator1_ServerValidate);

v.Validate ;

if not v.IsValid then

  ...

 

Agora está tudo certo. Se o valor inserido não confirmar a regra de validação, o texto da mensagem de erro será exibido na grid – exatamente abaixo da entrada errada.

Delphi sem limites

Já descobrimos como adicionar controles às células da grid, como acessa-los e como atribuir eventos a eles com código Delphi. Agora, estamos próximos de nossa meta final: criar o DataGrid somente pela codificação no Delphi, isto é, sem nenhuma intervenção de tempo de design no arquivo .aspx. Sim, isso é possível. Existem mais alguns truques para fazer com que tudo funcione corretamente.

Criar uma grid em tempo de execução usando as colunas geradas por default é fácil. Normalmente, o usuário usará o método Page.Controls.Add para colocá-lo na página depois de criar uma instância. Definir a propriedade ID irá impedir a atribuição de default dinâmicos – e desse modo desconhecido para nós ao codificar o ID.

Tenha sempre o hábito de atribuir IDs ao criar objetos no ASP.NET. Esse é praticamente o único caminho seguro para o objeto no código. Outra dica é usar um Placeholder e adicionar a instância da grid à sua coleção de controles (Controls Collection), e não à página (Page). Isso garantirá que os controles adicionados por meio de programação ao container da grid aparecerão entre as tags do formulário, e o erro 'control... must be placed inside a form tag with runat=server' não ocorrerá.

Para criar as colunas do template, é necessário implementar a interface ITemplate. Ela contém apenas um método: InstantiateIn, que fornece acesso ao container.

Veja aqui um rápido exemplo de criação de uma CheckBox – coluna para os valores de uma tabela Boolean:

 

type

  MyTemplateColumn = class(System.Object, ITemplate)

  private

    FColumnName: string;

  public

    procedure set_ColumnName(const Value: string);

  public

    property ColumnName: string read FColumnName write set_ColumnName;

    procedure InstantiateIn(Container:Control);

    procedure OnDataBinding(sender: System.Object; e: System.EventArgs);

  end;

  

procedure MyTemplateColumn.InstantiateIn(container: Control);

var

  Cb: CheckBox;

begin

  cb := CheckBox.Create ;

  cb.ID :='MycbID';

  Container.Controls.Add(cb);

  Include(cb.DataBinding ,OnDataBinding);

end;

 

procedure MyTemplateColumn.OnDataBinding(sender: TObject; e:System.EventArgs);

var

  Mycontainer: DataGridItem;

  MyCheckBox: CheckBox;

begin

  MyCheckBox:= CheckBox(sender);

  MyContainer:= DataGridItem(MyCheckBox.NamingContainer);

  MyCheckBox.Checked := System.Convert.ToBoolean(DataRowView(MyContainer.DataItem).Item [FColumnName ]) ;

end;

 

Agora, podemos simplesmente criar uma instância do objeto que implementa a Interface e a atribui a um template em uma coluna de template:

 

Tc := TemplateColumn.Create ;

myTemp:= MyTemplateColumn.Create  ;

myTemp.ColumnName := 'picture_IsPrinted';

tc.HeaderText :='Printed';

tc.ItemTemplate := myTemp;

 

E isso é tudo! Agora nós temos todas as ferramentas para criar um ambiente 'enriquecido' com diferentes controles Web DataGrid, para editar ou excluir dados e tudo o mais apenas com o código Delphi. A única etapa de design foi colocar o Placeholder no form.

O formulário e o code behind são separados, mas podem ser acessados entre si. Cabe ao desenvolvedor decidir quanto design visual ou 'puro' código Delphi.NET ele irá investir no projeto.

Ao examinar o Delphi 2005, é possível encontrar, mesmo quando ocultas ou não documentadas suficientemente, oportunidades reais para a programação Web no modo Delphi, de maneiras não existentes nas versões anteriores.

Com as classes Partial e outras melhorias, o ASP.NET 2.0 em breve alterará novamente o ambiente de programação de Internet do Delphi e ampliará ainda mais essas oportunidades.