terça-feira, 13 de março de 2012

Grids Dinamicos

Genexus atende muito bem aos casos em que as informações estão comportadas em tabelas previamente definidas, planejadas inicialmente por meio de transações, estruturas, atributos, ou seja no momento do design do software, mas o que dizer em situações que temos o conjunto a ser definido de dados somente em runtime? em outras palavras, quem define esse conjunto, por exemplo, seria o usuário por meio de uma interface.

Esse tema remete a vários problemas de programação, uma lista extensa que não cabe aqui explorar, mas o que mais me interessa nesse instante é a apresentação dessa estrutura nova, em uma situação em que não sabemos de antemão quais atributos deverão ser apresentados ao usuário.

Portanto, separemos o tema em dois, o armazenamento e em seguida a apresentação, e exploremos somente este último, por enquanto.

Grid Dinâmico

O controle Grid é um dos componentes mais utilizados e importantes na interface Genexus, e isso é facil de explicar porque, pois o mesmo é um mecanismo que se encarrega de selecionar, filtrar, apresentar, pesquisar informações armazenadas em uma tabela dita estendida, ou seja, a partir de uma determinada tabela base, todas as relacionadas N-1 a essa, em modo cascata, ou seja, atingindo aos niveis mais baixos e distantes do diagrama com um unico controle. Quer mais?

Infelizmente, tem um 'defeito', opera sob o modelo conceitual Genexus e claro, somente com as regras definidas pelo Genexus, atributos, tabelas pertencentes a esse modelo conceitual, em outras palavras, para 99,9% dos casos atende sem maiores dificuldades pois Genexus opera de forma muito eficaz em modo comportado.

Não sei a respeito dos seus problemas de programação, mas de vez em quando enrosco nesse 0,1% da estatística, com situações onde o modelo comportado não atende, ou mesmo, por pura frescura, desejo apresentar uma interface diferente para o usuário.  Vamos assumir essa segunda possibilidade, ok.

Como fazer então? para um grid tradicional é necessário um atributo previamente criado em alguma estrutura de transação, é necessário colocar esses atributos nas colunas do grid, e isso somente pode ser realizado em modo design?  A resposta: gxuiGrid.

gxuiGrid x gxuiGridExtension

Genexus implementa o grid do tipo gxui em duas formas distintas, o gxuiGrid tradicional, e o gxuiGridExtension, este ultimo trata de converter um grid tradicional Genexus no padrão visual do gxui, o resultado é ótimo em ambos os casos.

Existe no entanto uma diferença significativa entre os componentes: colunas dinâmicas e mecanismos tradicionais de carga e recuperação.

gxuiGrid
gxuiGridExtension
colunas dinâmicas
sim
nao
conteúdo dinâmico
sim
sim
evento Refresh
não
sim
evento Load
não
sim
for each line
não
sim

Para você entender direito, vou simplificar, com o gxuiGrid você tem mais flexibilidade para montar o que deseja mas não tem para recuperar a informação do Grid. Com o gxuiGridExtension você tem um modelo tradicional de carga, design, ..., mas com a aparência do gxuiGrid, mas sem tanta flexibilidade assim.  Portanto, existe espaço para dois sobreviverem, e para o gxuiGrid, uma necessidade de melhoria para que se permita por exemplo utilizar um for each line no mesmo.  Se seu problema se resume a apresentar a informação, então você está tranquilo, a questão é a recuperação dos dados para exportá-los para o Excel, por exemplo.

Vamos ao Exemplo

Seguindo a linha do Genexando vamos a um exemplo simples para não complicar muito a vida.  De quebra, vamos carregar um gxuiGrid com um conjunto variável de dados.  No exemplo, temos uma tabela, Estrutura, e na mesma diversos atributos (Titulo, CampoNome, Width, Hidden), que armazenam a composição desejada no gxuiGrid.  Essa tabela é responsável por manter a estrutura do Grid.
 for each
  if &tam > 0
    &gxuicoluna = new()
  endif
  &gxuicoluna.header = EstruturaTitulo.Trim()
  &gxuicoluna.dataIndex = EstruturaCampoNome.Trim()
  &gxuicoluna.width = EstruturaWidth
  &gxuicoluna.css = 'font-size:12px; color:#000000;'
  &gxuicoluna.dataType = gxuiDataType.string
  if EstruturaHidden =1
     &gxuicoluna.hidden = gxuiBoolean.True
  else
     &gxuicoluna.hidden = gxuiBoolean.False
  endif
  &gxuiGridColumnModel.Columns.Add(&gxuicoluna)
  &tam = 1
endfor

Para que funcione direitinho, carregue a tabela Estrutura com a definição dos campos que deseja colocar no Grid. No exemplo, utilizei no campo EstruturaCampoNome nomes simples como Coluna01, Coluna02, ... e por ai vai. A variável &gxuicoluna do tipo gxuiGridColumn, é utilizada para carregar a coleção de colunas em &gxuiGridColumnModel.  Veja que para simplificar poderiamos utilizar aqui um DataProvider, mas propositalmente coloquei em um for...each, para exercitar um pouco a respeito de coleções.


Uma vez construido o Grid, agora o foco é carregá-lo com alguma coisa. O segredo é ter uma coleção em que os nomes dos itens coincidam com os nomes das colunas definidas para o gxuiGrid, como por exemplo o SDT abaixo.
 
E a carga pode ser algo simples como a apresentada a seguir.
for &it = 1 to 10
  &gxuiGridDataItem.Coluna01 = str(&it * 1)
  &gxuiGridDataItem.Coluna02 = str(&it * 2)
 
&gxuiGridDataItem.Coluna03 = str(&it * 3)
  &gxuiGridDataItem.Coluna04 = str(&it * 4)
  &gxuiGridDataItem.Coluna05 = str(&it * 5)
  &gxuiGridData.Itens.Add(&gxuiGridDataItem)
  &gxuiGridDataItem = new()
endfor

A variável &gxuiGridData deve ser do mesmo tipo do SDT gxuiGridData, e a variável gxuiGridDataItem do tipo gxuiGridData.Item.


Antes de finalizar mais uma dica, na propriedade do gxuiGrid, não se esqueça de definir a variável que contém a carga &gxuiGridData, e o elemento inicial da coleção, que no nosso SDT se chama Itens.


Conclusão

Para quem está acostumado com a normalidade do Grid tradicional do Genexus, o gxuiGrid assusta um pouco, mas veja que vale a pena estudá-lo, dá pra pensar quantas excelentes oportunidades ele abre? de fato o controle é legal mesmo, portanto só nos resta agradecer ao pessoal da Artech pelo esforço para disponibilizá-lo para nós.

Quer aprender mais? instale a kb do RSSReader, disponivel no gxserver, e veja também como funciona o gxuiGridExtension