

| com exemplos em VB |
| Componente para deixar forms em Vb semelhantes às telas do winnamp |
| Componente para colocar sua aplicação VB no Systray |
| Componente para transformar sua aplicação VB em serviço |
| Ferramentas úteis para quem usa Olap Server |
| |

![]() |
||||||||
|
|
||||||||
Por Dennes
Torres dennes@bufaloinfo.com.brDennes Torres possui as certificações MCAD, MCSD,MCSE, MCDBA e MCT. Atualmente atua Como diretor da Búfalo Informática, líder do grupo de usuários DevASPNet no Rio de Janeiro e membro da liderança dos grupos getWindows e devSQL, também do Rio de Janeiro, podendo sempre ser encontrado na lista de discussão do grupo DevASPNet (devaspnet-subscribe@yahoogrupos.com.br) bem como nas reuniões do grupo. Mantém dois blogs em http://cidadaocarioca.blogspot.com |
|
|
|
|
| GridViews com Checkbox e um pouco mais | |
|
|
|
Utilizar checkbox em uma gridview é uma necessidade muito comum para marcar elementos da gridview, por exemplo para fazer uma deleção.
O ASP.NET possui muitos truques que facilitam consideravelmente a realização de tarefas como esta - e até mais complexas. Porém, como são truques pouco conhecidos, tem sido bem sub-utilizados. Desta forma mesmo que você já tenha realizado tarefas como esta, provavelmente vai descobrir alguns truques novos neste artigo.
Exemplo 1 : Deletando registros com uma checkBox
1) Crie um SQL Data Source
2) Configure o SQL Data Source para apontar para o banco Northwind, tabela produtos (produtos, não products), trazendo os campos productid, productname, unitprice e unitsInStock
Durante a configuração do datasource, utilize o "Advanced" para marcar a opção "Generate Insert, Update, Delete"
3) Crie uma gridview ligada a este SQL Data Source
Habilite paginação, ordenação e faça um auto-format.
4) Na smart tag, selecione "Edit Columns"
5) Adicione um templatefield antes da coluna productID
6) Com o botão direito na gridview, selecione "edit templates"->column[0]
7) Insira uma checkbox no ItemTemplate, dê o nome de chkMarcar
8) Com a checkbox selecionada, clique em split
9) Inclua o seguinte atributo na tag da checkbox :
1: idProduto='<%# 1: # eval("productid") %>'
Neste ponto estamos fazendo uso de vários conceitos importantes :
Qualquer atributo incluido em uma tag de webcontrol que não seja reconhecido pelo webcontrol é automaticamente renderizado no client, como um atributo HTML. É isso que acontecerá com "idProduto"
O HTML aceita atributos personalizados. A tag input - que vai ser gerada pela checkbox - não possui atributo idProduto (Claro!), mas o HTML aceitará o atributo.
Os webcontrols mantém todos os atributos renderizados na tag na propriedade attributes, mesmo que sejam atributos personalizados como o caso de "idProduto"
10) Clique novamente em design
11) Entre novamente na edição do template
12) Com a checkbox selecionada, clique no botão do raio (na janela de propriedades), digite MarcouItem no evento checkedchange e pressione ENTER
13) Monte o seguinte código :
Dim marcados As New List(Of Integer)Protected Sub MarcouItem(ByVal sender As Object, ByVal e As System.EventArgs)If sender.checked Thenmarcados.Add(sender.attributes("IdProduto"))End IfEnd SubNeste exemplo nunca teremos casos de uma checkbox sendo desmarcada. Se o usuário clicar na paginação ou ordenação da grid as checkbox marcadas serão desmarcadas por causa do databind() que é executado na gridview. Se clicar no botão deletar, os registros serão eliminados - portanto não poderão ser desmarcados. Desta forma, neste exemplo nunca teremos um caso de checkbox sendo desmarcada.
14) Habilite a propriedade showfooter da gridview
15) Entre novamente na edição do template
16) Inclua um botão no footerTemplate - chame de cmdDeletar e coloque o text como Deletar
O fato do botão ficar dentro ou fora da grid não importa - é uma questão de gosto
15) Dê um duplo clique no botão para gerar o evento click e programe o seguinte :
Protected Sub cmdDeletar_Click(ByVal sender As Object, ByVal e As System.EventArgs)For Each p In marcadosSqlDataSource1.DeleteParameters("Productid").DefaultValue = pSqlDataSource1.Delete()NextEnd SubQuando um postback ocorre, existe uma sequencia de execução no eventos da página. Segundo esta sequencia, todos os eventos de change são executados antes que o evento de click - que causou o postback - seja executado.
Isso faz com que o "MarcouItem" seja executado para todas as checkbox marcadas antes que o click do botão deletar seja executado. Desta forma, quando o click do botão deletar é executado a coleção "marcados" já está preenchida exatamente com os itens que devem ser deletados.
16) Teste a aplicação
O uso do atributo na checkbox em conjunto com um bom uso da sequencia de eventos da página evita soluções mais mirabolantes como uma verificação de cada checkbox para descobrir quais estão marcadas.
Exercício 2 : Marcar todos
É muito frequente a necessidade de marcar ou desmarcar todas as checkbox de uma grid. Isso precisa ser feito com programação no client, do contrário seria um excesso de idas ao servidor.
Atualmente temos como recurso o JQuery para fazer isso, seria realmente muito simples, especialmente no próximo ano, quando o JQuery estará totalmente integrado ao ASP.NET.
Porém para utilizar o JQuery atualmente precisamos vincular os arquivos javascript do JQuery no projeto. Para não entrar nesta complexidade, faremos um exemplo apenas com código javascript, sem o JQuery.
1) No source, dentro da tag Head, crie a seguinte função :
1: <script language="javascript">2: function CheckAllDataGridCheckBoxes(aspCheckBoxID, checkVal) {3:4: re = new RegExp(aspCheckBoxID)5:6: for(i = 0; i < document.forms[0].elements.length; i++) {7:8: elm = document.forms[0].elements[i]9:10: if (elm.type == 'checkbox') {11:12: if (re.test(elm.name)) {13:14: elm.checked = checkVal15:16: }17: }18: }19: }20: </script>
A função recebe como parâmetro o nome da checkbox e um valor (true/false) que deve ser utilizado para marcar ou desmarcar a checkbox.
O nome da checkbox é utilizado na montagem de uma expressão regular para fazer a busca por todos os objetos do form que são checkbox e possuem este nome. Lembre-se que o "name" no client não é exatamente o id que damos no servidor, mas uma montagem envolvendo o nome dos containers em que o objeto está, por isso a busca utilizando uma expressão regular.
2) No template field que contém a checkbox, crie um <headertemplate>
3) No headertemplate, adicione o seguinte código :
1: <input type="checkbox"
id="chkAllItems" onclick="CheckAllDataGridCheckBoxes('chkMarcar', document.forms[0].chkAllItems.checked)" />Marcar Tudo
Estamos criando uma nova checkbox no cabeçalho da grid. Quando esta checkbox for clicada, vai chamar a função CheckAllDatagridCheckboxes passando como parâmetro o ID que a checkbox tem no servidor ("chkMarcar"). O 2o parâmetro precisa ser true ou false, para marcar ou desmarcar as caixas. Por isso, neste exemplo, é passado o próprio valor de checked desta checkbox que incluimos no header da grid : Se a checkbox do header for marcada, todas as outras são. Se for desmarcada, todas as outras são desmarcadas.
4) Teste a aplicação
Exercício 3 : Marcação através da paginação
Até o momento, se clicarmos na paginação ou ordenação dos dados todas as checkbox marcadas são perdidas, pois é feito um databind() da gridview e as checkbox são reconstruidas.
Vamos então montar uma solução que nos permita manter as checkbox marcadas mesmo através da paginação.
1) Substitua a variável "marcados" pelo seguinte código :
Public ReadOnly Property Marcados() As List(Of Integer)GetIf IsNothing(ViewState("marcados")) ThenViewState("marcados") = New List(Of Integer)End IfReturn (ViewState("marcados"))End GetEnd PropertyObservamos o seguinte :
Uma propriedade é a forma mais otimizada de uso do viewstate, pois centraliza o uso do viewstate apenas na propriedade e todo o resto da página faz uso da propriedade.
Como neste exemplo a informação sendo guardada é um objeto - e uma coleção - a propriedade pode ser readonly sem problema, isso não afeta o uso da coleção. Lembre-se de que o acesso está sendo feito a um ponteiro para a coleção.
Devido ao return ser feito diretamente do objeto no viewstate, não é necessário trabalho adicional de gravação. Conforme ocorrerem Adds e Removes o viewstate está sendo atualizado - na verdade tudo aponta para o mesmo objeto.
2) Altere o código do "MarcouItem" :
Protected Sub MarcouItem(ByVal sender As Object, ByVal e As System.EventArgs)If sender.checked ThenMarcados.Add(sender.attributes("IdProduto"))ElseMarcados.Remove(sender.attributes("IdProduto"))End IfEnd SubTeremos agora também situações em que a checkbox estará sendo desmarcada.
3) Crie o evento rowdatabound da gridview e programe o seguinte :
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBoundIf e.Row.RowType = DataControlRowType.DataRow ThenIf Marcados.IndexOf(e.Row.DataItem("productid")) <> -1 ThenDim chk As CheckBoxchk = e.Row.FindControl("chkMarcar")chk.Checked = TrueEnd IfEnd IfEnd SubO simples fato de mantermos a coleção de "Marcados" no viewstate não garante que as checkbox ficarão marcadas, elas continuarão sendo "apagadas" a cada databind(). Torna-se necessário então fazer com que no databind() a coleção de marcados seja verificada para que a checkbox seja marcada, é isso que faz o rowdatabound, que é processado para cada linha sempre que um databind ocorre.
4) Teste a aplicação
Curiosidade : Não é necessária nenhuma ação adicional para "gravar" as marcações, lembre-se que o checkedchange vai ocorrer antes de qualquer ação que vá ao servidor, isso inclui paginação e ordenação, antes do databind o checkedchange é feito e guarda as marcações no viewstate, que é lido novamente após o databind()
Exercicio 4 : Atualização de dados
Uma situação um pouco mais complexa do que o trabalho com as checkbox é uma atualização em bloco : Deixar o usuário alterar dados em todos os registros da tela e com um único click em um botão gravar realizar a gravação de tudo que foi alterado. Vamos então implementar este exemplo
1) Transforme as colunas productName, UnitPrice e UnitsInStock em templates
2) Clicando com o botão direito na grid, entre na edição do template de productName
3) Apague o label contido em ItemTemplate
4) Mova a textbox contida em EditItemTemplate para ItemTemplate e dê o nome de txtProduto
5) Repita os itens 2, 3 e 4 para UnitPrice e UnitsInStock utilizando os nomes de txtPreco e txtEstoque
6) Na tag das textbox txtProduto, txtPreco e txtEstoque insira o seguinte atributo :
1: idProduto='<%# 1: # eval("productid") %>'
7) Com o botão direito no site, clique em Add New Item e adicione uma nova classe chamada "Produtos", com o seguinte código :
Public Class ProdutoPublic productid, unitsinstock As IntegerPublic productname As StringPublic unitprice As DecimalEnd Class8) Nas propriedades da caixa txtProduto (terá que editar o template novamente), clique no raio e, no evento TextChanged, digite "AlterouDados" e pressione ENTER
9) Nas propriedades das caixas txtPreco e txtEstoque (terá que editar o template de cada uma novamente), clique no raio e, no evento textchanged de cada uma selecione a mesma rotina - AlterouDados.
10) Crie na página uma variável "Lista" da seguinte forma :
Dim lista As List(Of Produto)Depois do usuário ter alterado diversos registros de produtos e clicado em gravar, identificaremos uma por uma as linhas alteradas pelo usuário através do evento textChanged. Para guardar os dados da linha alterada até que chegue a hora de gravar (o que acontece no mesmo postback, no evento de click do botão) utilizaremos a classe Produto.
Assim sendo, a variável "lista" irá conter todos os produtos que sofreram alguma alteração pelo usuário.
11) Programe a sub "AlterouDados" da seguinte forma :
Protected Sub AlterouDados(ByVal sender As Object, ByVal e As System.EventArgs)Dim id As Integerid = sender.attributtes("idproduto")If Not (From p In lista Where p.productid = id Select p).Any() ThenDim gvr As GridViewRowDim txtproduto, txtpreco, txtestoque As TextBoxgvr = GridView1.Rows(AcharDatakey(id))txtproduto = gvr.FindControl("txtProduto")txtpreco = gvr.FindControl("txtpreco")txtestoque = gvr.FindControl("txtestoque")lista.Add(New Produto With _{.productid = id, .productname = txtproduto.Text, _.unitprice = txtpreco.Text, _.unitsinstock = txtestoque.Text})End IfEnd SubPublic Function AcharDatakey(ByVal id As Integer) As IntegerFor i = 0 To GridView1.DataKeys.Count - 1If GridView1.DataKeys(i).Value = id ThenReturn iEnd IfNextReturn -1End FunctionEsta sub será executada para qualquer dos 3 campos de produto que tenha sido alterado. Observe a sequencia do que esta sub faz :
A) Recupera o idProduto da coleção de atributos da caixa
B) Verifica se o idProduto já está na coleção "lista" - neste exemplo utilizamos Linq
Se o usuário alterar mais de um campo do mesmo produto, esta rotina será executada mais de uma vez para o mesmo produto, por isso esse cuidado é necessário.
C) Obtem os dados do produto, utilizando findControl
D) Adiciona o produto na coleção Lista - utilizamos uma nova síntaxe do VB 9 para facilitar isso
12) Edite o template da primeira coluna e insira no rodapé um botão com o nome de cmdGravar e text="Gravar"
13) Programe o click do cmdGravar da seguinte forma :
Protected Sub cmdGravar_Click(ByVal sender As Object, ByVal e As System.EventArgs)For Each p As Produto In listaSqlDataSource1.UpdateParameters("ProductId").DefaultValue = p.productidSqlDataSource1.UpdateParameters("ProductName").DefaultValue = p.productnameSqlDataSource1.UpdateParameters("UnitPrice").DefaultValue = p.unitpriceSqlDataSource1.UpdateParameters("UnitsInStock").DefaultValue = p.unitsinstockSqlDataSource1.Update()NextEnd SubA sequencia de eventos da página fará com que todos os textchanged sejam executados antes desta rotina de click, consequentemente quando esta rotina de click for executada a coleção "lista" já estará preenchida com todos os produtos que houverem sido alterados.
14) Teste a aplicação.
Estes exemplos demonstram como os webControls do ASP.NET e a sequencia de eventos da página possuem muitos truques que devem ser muito cuidadosamente trabalhados pelo desenvolvedor para que tarefas complexas acabem sendo solucionadas de forma bem simples.
Neste último exemplo, passos adicionais seriam a inclusão de validadores e fazer com que as alterações sejam mantidas através da paginação, o que pode ser feito de forma equivalente ao trabalho com as checkbox, transformando "lista" em uma coleção no viewstate e programando o rowdatabound para preencher as textbox com os valores alterados.
Descubra muitos outros truques com o ASP.NET em nosso CD de Acesso a Dados com ASP.NET e nosso DVD de Segurança no ASP.NET
Veja abaixo os comentários já enviados :
| Nome : Suzi | E-Mail : |
| Perfeito, fácil de entender, na primeira já deu certo. Obrigada |
|