Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de Usuários
»Células Acadêmicas«
intcontpiada : 118
Video Conferência
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
Faça um pequeno teste com 10 questões de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programação com nosso treinamento on-line de lógica de programação
.:.
Veja nosso calendário de treinamentos
Gostou da Página?
Então

para um amigo!
 





Por Dennes Torres
dennes@bufaloinfo.com.br
Dennes 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

Pesquisa personalizada
Pesquisar Dicas:






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 Then
            marcados.Add(sender.attributes("IdProduto"))
        End If
    End Sub

Neste 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 marcados
            SqlDataSource1.DeleteParameters("Productid").DefaultValue = p
            SqlDataSource1.Delete()
        Next
    End Sub

Quando 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 = checkVal
  15:             
  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)
        Get
            If IsNothing(ViewState("marcados")) Then
                ViewState("marcados") = New List(Of Integer)
            End If
            Return (ViewState("marcados"))
        End Get
    End Property

Observamos 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 Then
            Marcados.Add(sender.attributes("IdProduto"))
        Else
            Marcados.Remove(sender.attributes("IdProduto"))
        End If
    End Sub

Teremos 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.RowDataBound
 
        If e.Row.RowType = DataControlRowType.DataRow Then
            If Marcados.IndexOf(e.Row.DataItem("productid")) <> -1 Then
                Dim chk As CheckBox
                chk = e.Row.FindControl("chkMarcar")
                chk.Checked = True
            End If
        End If
 
    End Sub

O 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 Produto
    Public productid, unitsinstock As Integer
    Public productname As String
    Public unitprice As Decimal
End Class

8) 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 Integer
        id = sender.attributtes("idproduto")
 
        If Not (From p In lista Where p.productid = id Select p).Any() Then
            Dim gvr As GridViewRow
            Dim txtproduto, txtpreco, txtestoque As TextBox
            gvr = 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 If
    End Sub
    
    Public Function AcharDatakey(ByVal id As Integer) As Integer
        For i = 0 To GridView1.DataKeys.Count - 1
            If GridView1.DataKeys(i).Value = id Then
                Return i
            End If
        Next
        Return -1
    End Function

Esta 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 lista
            SqlDataSource1.UpdateParameters("ProductId").DefaultValue = p.productid
            SqlDataSource1.UpdateParameters("ProductName").DefaultValue = p.productname
            SqlDataSource1.UpdateParameters("UnitPrice").DefaultValue = p.unitprice
            SqlDataSource1.UpdateParameters("UnitsInStock").DefaultValue = p.unitsinstock
            SqlDataSource1.Update()
        Next
    End Sub

A 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

 

 

 



Envie seus comentários sobre este artigo

Nome :

E-mail :

Comentários :


Avise-me quando houverem novos comentários nesta página

Veja abaixo os comentários já enviados :

Nome : Suzi E-Mail :
Perfeito, fácil de entender, na primeira já deu certo.
Obrigada
Nome : Carlos A A Neves E-Mail : caan@bol.com.br
¡Gracias!
Me ayudó mucho.
Voy a mantener un ojo en todos sus posts.