msdn25_capa.jpg

Clique aqui para ler todos os artigos desta edição

 

Personalizando o DetailsView e o FormView

 

 

O ASP.NET 1.x introduziu alguns controles data-bound poderosos e úteis. Porém, nenhum foi especificamente projetado para gerenciar a visualização (view) de um único registro. Quando você constrói views “master/detail”, você precisa exibir os conteúdos de um único registro. Então quando o usuário selecionar um registro mestre de uma lista ou em um grid, você tipicamente desejará que a aplicação mostre todos os campos disponíveis. Você pode usar o DataGrid e outros controles para exibir um único registro, mas essa abordagem é apenas um “quebra-galho”. Para um verdadeiro controle “record-view” em ASP.NET 1.x, você tem que comprar um ou construir o seu próprio.

Atenta para esse problema, a Microsoft acrescentou alguns novos  controles no ASP.NET 2.0 que permitem criar views de um único registro. Especificamente, você pode usar os controles DetailsView e FormView junto com o DataGrid e GridView para atingir essa funcionalidade. Funcionalmente falando, FormView e DetailsView são quase idênticos. Eles diferem principalmente no layout da saída gerada. O FormView permite o total controle do layout, possibilitando a definição de um formulário personalizado contendo controles para exibir e editar valores de campos. Por outro lado, DetailsView é restrito a um layout tabular com duas colunas: cabeçalho e valor. Porém, a célula de valor pode ser personalizada com templates.

Essas características provêem uma importante funcionalidade que antes estava faltando. E apesar de ainda serem um pouco limitadas, sempre existe um jeito de contornar essas limitações. Nesta coluna, nos aprofundaremos na interface de programação dos controles DetailsView e FormView, para explicar as mudanças que irão tornar estes controles mais versáteis.

Problemas com dados do mundo real

A Figura 1 mostra um exemplo de página ASP.NET do tipo master/detail, que usa DetailsView e GridView (para o código completo, veja o download). Note que a aplicação provê só TextBoxes para editar os dados, independentemente do tipo de dados que são editados. Apesar disso estar correto para alguns tipos de dados, não é o ideal para todos. Como proceder, por exemplo, caso uma coluna de dados trate de uma data?

 

image002.jpg

Figura 1. GridView e DetailsView em ação

Ou se fosse então um campo country (país)? O nome do país vai ser armazenado em um banco de dados que você pode querer pesquisar, portanto a consistência do modo com que um nome de país é expresso faz diferença. Neste caso, uma lista dropdown seria uma escolha melhor. Manteria os dados consistentes.

A página na Figura 1 foi composta usando o GridView e DetailsView, que utilizam fontes de dados (DataSources) associadas para selecionar e atualizar os registros exibidos. Uma vez que o usuário editou um registro e clicou no botão Update, o controle DetailsView executa o comando Update da fonte de dados associada e atualiza a view. Até aqui tudo bem.

Nota: Neste artigo, o termo “fonte de dados” se refere a qualquer um dos tipos de Data Sources disponíveis no ADO.NET 2.0, como SqlDataSource, AccessDataSource e ObjectDataSource.

Na mesma página, o controle GridView exibe uma pré-visualização do mesmo registro. Porém, a linha correspondente não é atualizada para refletir as mudanças. Isso não nos surpreende, pois não há nenhuma ligação entre os controles GridView e DetailsView. Quando o usuário clicar para atualizar o DetailsView, acontece um postback na página. Como resultado, todos os controles da página, inclusive o GridView, são reconstruídos. Tipicamente, quando a página está carregando, o GridView, assim como outros controles, se reconstroem a partir do ViewState. Se o ViewState não está disponível (por exemplo, se está desabilitado), o GridView acessará a fonte de dados associada.

A fonte de dados do controle não é armazenada no ViewState, mas sua representação visual é. A representação visual de uma fonte de dados é a parte da mesma que é exibida nas linhas do grid. Os objetos que representam cada linha do grid serializam todos seus conteúdos para o ViewState, inclusive os itens de dados neles contidos.

Depois que a página estiver carregada e todos os controles forem inicializados, a página poderá processar o evento postback. Neste caso, o evento postback é o Update do registro de detalhe, seguido pela atualização do DetailsView. Como resultado, o controle DetailsView e sua grid “master”, estão agora fora de sincronia. O GridView não refletirá as mudanças automaticamente, porque seu estado foi restabelecido antes que o Update atual fosse realizado.

Se observarmos o SQL Profiler, veremos muita atividade com a monitoração de todos os comandos de banco de dados executados, quando o botão Update foi clicado, para salvar as mudanças em um DetailsView. O primeiro comando executado é select * from Customers que preencherá o GridView. A seguir, há um comando update que atualiza o banco de dados. Finalmente, há uma declaração select que lê o registro modificado, para atualizar o DetailsView. (Note que este é um exemplo onde o GridView tem o ViewState desabilitado e os controles de fonte de dados associados têm o caching desabilitado).

Mantendo dados sincronizados

A solução para dados que estão fora de sincronia consiste em simplesmente forçar o GridView a atualizar sua fonte de dados, depois que o registro detalhe foi atualizado. Felizmente, o controle DetailsView dispara um evento ItemUpdated, que pode ser usado para manter o mestre e as views detalhe em sincronia, como é feito com o seguinte manipulador de evento:

 

Sub OnItemUpdated(ByVal sender As Object, ByVal e As DetailsViewUpdatedEventArgs)

    GridView1.DataBind()

End Sub

 

Porém, quando o controle de fonte de dados do GridView tiver o caching habilitado, isso pode não funcionar. O método DataBind dispara corretamente o processo associado mas, ao invés de examinar o banco de dados, ele na verdade recarrega os dados antigos do cache. Em controles de fontes de dados, o caching é desabilitado por padrão e pode ser habilitado através da configuração da propriedade EnableCaching para “true”. Apesar de o caching ser uma melhor prática, só é suportado quando são usados objetos DataSet ou DataTable para retornarem dados (se você usar o ObjectDataSource com coleções personalizadas, a infra-estrutura dos controles de fonte de dados não provê capacidade de caching. O caching ainda é possível, mas deve ser codificado dentro do modelo do objeto personalizado, associado ao ObjectDataSource).

Quando o caching é habilitado, seu padrão é uma política de expiração baseada em tempo. A duração padrão é 0 (zero), especificando um período de tempo infinito. A menos que você especifique uma duração diferente de zero (em segundos), os dados em cache nunca expirarão e você não terá como atualizar a view, a não ser fazendo a ligação a outra fonte de dados.

Devemos considerar duas alternativas. A primeira seria montar um mecanismo de dependência de cache de banco de dados, via propriedade SqlCacheDependency do controle de fonte de dados. Apesar de inteligente e poderosa, essa abordagem requer mudanças no banco de dados físico, adicionando triggers, stored procedures e até mesmo uma nova tabela. No entanto, um mecanismo para desabilitar o cache de banco de dados, alivia a responsabilidade de ter que fazer qualquer Update adicional de dados em cache, para manter as views em sincronia.

A segunda abordagem é usar a propriedade CacheKeyDependency do controle de fonte de dados, como mostrado a seguir:

 

...

Quer ler esse conteúdo completo? Tenha acesso completo