Exibindo Arquivos e Imagens

Muitas vezes em nossos sistemas de internet, precisamos exibir uma listagem os arquivos que estão no disco do servidor para o Usuário, seja para uma simples conferência ou até mesmo para edição do mesmos (quando possível).

Há outras ocasiões onde esses arquivos são Imagens, onde devem ser exibidas amigavelmente para o Usuário. Neste caso, não basta exibir o seu nome, ou suas características, mas sim a Imagem propriamente dita.

O .NET Framework nos fornece diversas classes para acesso à arquivos e diretórios. Todas contidas dentro do Namespace System.IO. Neste artigo veremos sobre a classe DirectoryInfo e sobre o método GetFiles().

A Classe DirectoryInfo

Com a Classe DirectoryInfo temos acesso as informações de um determinado diretório, incluindo seu Nome, Path, etc., passando em seu construtor um parâmetro que identifica o caminho do diretório a ser retornardo seus respectivos arquivos. Com isso, temos acesso ao método GetFiles(), qual retorna uma lista contendo os de arquivos do diretório em questão. Neste mesmo método, temos um Overload, que recebe como parâmetro um “SearchPattern”, ou seja, uma String que você informa a extensão dos arquivos a serem retornados.

Exibindo Arquivos TXT de um Diretório (DataGrid)

Como vimos um pouco acima, em determinados momentos precisamos exibir uma listagem dos arquivos de um determinado diretório para o Usuário. Com isso, utilizaremos o controle DataGrid para a exibição destes arquivos.

Sabendo-se que o método GetFiles() retorna uma lista dos arquivos do diretório, a idéia é criarmos as BoundColumns com as propriedades do arquivo, como: Name, FullName (Path), e LastWriteTime (Data da Última Modificação). Arraste um controle DataGrid na tela, e clique com botão direito em cima do mesmo, vá até Property Builder e em seguinda clique em Columns. Você deverá adicionar três BoundColumns, informando o Nome, Caminho e Data da Última Modificação do Arquivo. A figura abaixo ilustra o processo:

Figura 1 – Property Builder do DataGrid.

As Propridades devem ficar conforme a tabela abaixo:

Coluna 1 Coluna 2 Coluna 3
Header Text Nome do Arquivo Path Ultima Modificação
Data Field Name FullName LastWriteTime

Feito isso, seu DataGrid deverá ficar como a imagem abaixo:

Figura 2 – DataGrid já desenhado.

Agora nos resta fazer a codificação para que o método GetFiles() popule o DataGrid. Temos agora que utilizar o evento Page_Load do WebForm, para populá-lo. O código ficará da seguinte forma:

1
2
3
4
5
6
7
8
9
10
 
Private Sub Page_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
    If Not Page.IsPostBack Then
        Dim dirInfo As New DirectoryInfo(Server.MapPath(“Arquivos/”))
        With Me.dgArquivos
            .DataSource = dirInfo.GetFiles(“*.txt”)
            .DataBind()
        End With
    End If
End Sub
 
Código 1 – Carregando o DataGrid com arquivos TXT.

Como vemos, o método GetFiles recebe como parâmetro a string contendo a extensão do arquivo que desejamos recuperar do diretório, ou seja, serão retornados apenas arquivos com extensão “*.txt”. Ao rodar a aplicação o resultado deverá ser:

Figura 3 – DataGrid preenchido com a Listagem de Arquivos.

Exibindo Imagens (DataList)

Neste caso, temos que exibir as imagens de um diretório no DataList. Não muda muito com relação ao exemplo anterior com TXT. A única diferença significativa é a mudança do controle de DataGrid para DataList.

Crie um novo WebForm contendo um controle DataList. Clique com o botão direito em cima do mesmo, e vá até a opção Property Builder. Defina a propriedade Columns como 3 e a propriedade Direction como Vertical, conforme a figura abaixo:

Figura 4 – Configurando o DataList.

Da mesma forma que fizemos para resgatar os arquivos *.txt no exemplo anterior, faremos aqui também, apenas mudando o SearchPattern para “*.jpg”, conforme o código abaixo:

1
2
3
4
5
6
7
8
9
10
 
Private Sub Page_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
    If Not Page.IsPostBack Then
        Dim dirInfo As New DirectoryInfo(Server.MapPath(“Imagens/”))
        With Me.dtlImagens
            .DataSource = dirInfo.GetFiles(“*.jpg”)
            .DataBind()
        End With
    End If
End Sub
 
Código 2 – Carregando o DataList com arquivos JPG.

Como estamos utilizando o DataList, precisamos apenas definir onde os campos irão ser colocados no HTML. Para isso, localize a seção ItemTemplate e AlternatingItemTemplate do DataList e defina:

1
2
3
4
5
6
7
 
<ItemTemplate>
    <img src = ‘Imagens/<%# DataBinder.Eval(Container.DataItem, “Name”) %>‘>
</ItemTemplate>
 
<AlternatingItemTemplate>
    <img src = ‘Imagens/<%# DataBinder.Eval(Container.DataItem, “Name”) %>‘>
</AlternatingItemTemplate>
 
Código 2 – Carregando o DataList com arquivos JPG.

Ao compilar, se nenhuma falha ocorrer, o resultado deverá ser conforme a figura abaixo:

Figura 5DataList carregado com as Imagens.

Conclusão: Vimos neste artigo o quanto é fácil manipularmos Diretórios e seus Arquivos com o Namespace System.IO e também a flexibilidade que as classes nos fornecem, permitindo o acesso rápido as suas propriedades e atribuindo essas listagens de arquivos e/ou diretórios aos controles, facilitando a vida do desenvolvedor.

Migrando de ASP para ASP.NET

Com a vinda do ASP.NET e o Visual Studio .NET, quem utiliza o ASP para o desenvolvimento de aplicações Web sentiu e sente dificuldades para tal migração, principalmente com o novo conceito de Code Behind que tem por finalidade de separar o código que é executado no servidor do HTML que é exibido no cliente.

Muitas vezes chegam até a pensar se é viável ou não a migração. E a resposta é sim. O ASP.NET nos traz uma nova forma de desenvolvimento para a Web, possibilitando construirmos aplicativos profissionais com uma grande facilidade, principalmente quando utilizamos o Visual Studio .NET como ferramenta de desenvolvimento.

Este artigo tem como finalidade mostrar aos desenvolvedores ASP como são realizados os mais frequentes processos, fazendo uma comparação entre ASP e depois em ASP.NET, iniciando com um overview sobre a plataforma .NET.

.NET Framework

O Microsoft .NET Framework é um conjunto de objetos para a construção de aplicativos, sejam eles Web, Windows ou Mobile. Atualmente ele se encontra em sua versão 1.1, e qual podemos utilizar o Visual Studio .NET 2003 para desenvolvemos sob ela.

CLR – Common Language Runtime

O Common Language Runtime (CLR) é o ambiente que gerencia a execução de código. Tradicionalmente ao criar um aplicativo, (em Visual Basic por exemplo), o mesmo é compilado em linguagem que o computador possa entender (0 e 1) e então o executa. Note que em diferentes tipos de computadores (PC’s e Machintoshes), você deverá recompilar o aplicativo para o mesmo se adaptar ao computador que vai utilizá-lo. Com a .NET Framework, isso funciona de forma diferente.

Em .NET Framework você utiliza uma linguagem de programação (sendo Visual Basic .NET ou Visual C# .NET) para escrever o código e a .NET Framework em conjunto com a CLR para compilar este código escrito. Mas ao invés deste código ser compilado para a linguagem nativa do computador, o mesmo é compilado para uma linguagem intermediária, chamada de MSIL (Microsoft Intermediate Language), que é uma forma abreviada de representar este código que você escreveu.

Tendo este código intermediário, ao executar o aplicativo o Common Language Runtime assume e compila o código, agora em linguagem nativa do computador por um compilador Just-In-Time (JIT), otimizando o melhor possível para aquele processador. Veremos abaixo as duas formas, com e sem o .NET Framework:

Figura 1 – Aplicativo sendo executado da forma tradicional.

 


Figura 2 – Com o .NET Framework.

Metadados

Quando compilamos nossos aplicativos ASP.NET, eles também são compilados para MSIL, criando assim o que chamamos de metadados que são informações descritivas sobre o aplicativo, dizendo o que o aplicativo pode fazer, a que pertence, etc.

A CLR utiliza esses metadados para descobrir de que forma executar esse aplicativo. Esse código que é executado pela CLR, é o que chamamos de código gerenciado. Isso faz com que o desenvolvedor não precise construir manulmente para gerenciar os recursos. Mas isso não é tudo que a CLR faz. Além disso, nos fornece a integração entre diferentes linguagens, tratamento de erros, entre outras características importantes para o desenvolvimento de nossas aplicações (Windows, Web ou Mobile).

Diferenças do ASP.NET em relação ao ASP

Entre os muitos benefícios fornecidos pelo ASP.NET tais como cache, compilação de código, segurança podemos destacar a facilidade no desenvolvimento, pois como vimos anteriormente, o código fica encapsulado dentro de um arquivo *.DLL, qual é preciso apenas utilizar o XCOPY para a distribuição, não havendo a necessidade do registro da mesma com o uso do REGSVR32.EXE, não tendo mais o “DLL Hell” (Inferno das DLL’s).

No ASP tinhamos o código que era executado dentro das tags <% … %> que atualmente não é mais compilado e seu uso não aconselhado, pois evita a mescla de código de servidor juntamente com o código HTML, o chamado spaghetti code.

Uma das grandes inovações é o CodeBehind. Com ele é possível separarmos o código do servidor do código HTML. O CodeBehind pode ser escrito em Visual Basic .NET ou Visual C# .NET e ao compilar o aplicativo esse código é encapsulado dentro da DLL, sendo necessário apenas o envio do arquivo ASPX para o servidor de produção. Ao criar um novo WebForm no Visual Studio .NET, são criados dois arquivos: o arquivo Arquivo.aspx (arquivo que contém o código HTML) e o Arquivo.aspx.vb ou Arquivo.aspx.cs (arquivo que contém o código que é executado no servidor). Quando o aplicativo é escrito em Visual Basic .NET, a extensão do arquivo é *.aspx.vb e sendo escrito em Visual C# .NET, a extensão será *.aspx.cs.

Abaixo veremos a estrutura do CodeBehind:

Figura 3 – Estrutura do CodeBehind dos arquivos ASPX.

O Fluxo

Poderão notar na primeira vez que executar o aplicativo, haverá um leve retardo. Isso ocorre devido a compilação do código que é realizado. Já na segunda vez esse processo não é efetuado, aumentando ainda mais a performance do aplicativo. Ao receber a solicitação de uma página, a mesma é compilada (caso seja a primeira vez), trata os eventos da Página e de seus controles, executa o código referente à esses eventos e finalmente gera o código HTML e envia ao browser. Abaixo a imagem ilustra o processo.

Figura 4 – Processo de execução de uma página ASPX.

As Linguagens de Programação

Vale lembrar que ASP assim como o ASP.NET não é uma linguagem de programação e sim uma tecnologia para desenvolvimento de aplicativos Web-Based. com isso, temos algumas linguagens em quais podemos escrever aplicativos ASP.NET, tais como: Visual Basic .NET, Visual C# .NET, C++ ou JScript.NET, que independentemente de qualquer linguagem que escrevemos, o código será sempre compilado para MSIL. Essas linguagens estão em conformidade com a CLS – Common Language Specification, que garante a conversação de aplicativos de diferentes linguagens. E todas as linguagens devendo ser 100% Orientada a Objetos.

Em ASP utilizavamos VBScript ou JavaScript para escrevemos os aplicativos, sendo os mesmos interpretados quando eram executados.

Hoje temos linguagens fortemente tipadas para isso, ou seja, por padrão devemos sempre especificar qual o tipo da variável qual estamos trabalhando, nos obrigando a declarar todas as váriveis.

Comparando ASP vs. ASP.NET (Códigos)

Abaixo será mostrado uma série de exemplos feitos em ASP e depois em ASP.NET para mostrar a diferença entre as duas tecnologias. Com esses exemplos ficará claro a facilidade de desenvolvimento de aplicativos feitos em ASP.NET.

Preenchendo DropDownList

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<select name = ‘cboareas’>”)
    Response.Write (“<option value = ”>Selecione…</option>”)
    While Not rs.EOF
        Response.Write (“<option value = ” & rs(“CategoryID”))
        Response.Write (“>” & rs(“CategoryName”) & “</option>”)
        rs.Movenext
    Wend
    Response.Write (“</select>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
8
9
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT * FROM Categories”, conn)
 
Me.DropDownList1.DataTextField = “CategoryName”
Me.DropDownList1.DataValueField = “CategoryID”
conn.Open()
Me.DropDownList1.DataSource = cmd.ExecuteReader
Me.DropDownList1.DataBind()
conn.Close()
 

Exibindo Grid’s de dados

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<table width = ‘100%’ align = ‘center’>”)
    While Not rs.EOF
        Response.Write (“<tr>”)
        Response.Write (“<td>” & rs(“CategoryID”) & “</tr>”)
        Response.Write (“<td>” & rs(“CategoryName”) & “</tr>”)
        Response.Write (“</tr>”)
        rs.Movenext
    Wend
    Response.Write (“</table>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT * FROM Categories”, conn)
 
conn.Open()
Me.DataGrid1.DataSource = cmd.ExecuteReader
Me.DataGrid1.DataBind()
conn.Close()
 

Formulários – Post

:: ASP
1
 
Response.Write(Request.Form(“TextBox1”))
 

 

:: ASP.NET
1
2
3
4
 
Private Sub Button1_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
    Response.Write(Me.TextBox1.Text)
End Sub
 

OBS.: Como o desenvolvimento de aplicações ASP.NET esta muito semelhante à aplicações Windows, agora basta darmos um duplo clique no botão e ali codificar, não havendo mais a necessidade da criação de uma nova página para processar o formulário.

Acesso à Banco de Dados

:: ASP
1
2
3
4
5
6
7
8
 
Dim conn
 
Set conn = Server.CreateObject(“ADODB.Connection”)
conn.ConnectionString = “CONNECTION_STRING”
conn.Open()
    ‘…
conn.Close()
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
conn.Open()
    ‘…
conn.Close()
 

Preenchendo um Formulario

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT TOP 1 * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<input type = ‘text’ name = ‘txtNome’ value = ‘” & rs(“CategoryName”) & “‘>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
8
9
10
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT Top 1 * FROM Categories”, conn)
 
conn.Open()
Dim dr As SqlDataReader = cmd.ExecuteReader
 
If dr.Read() Then
    Me.txtNome.Text = dr(“CategoryName”)
End If
conn.Close()
 

Lendo o conteudo de Arquivos TXT

:: ASP
1
2
3
4
5
6
7
 
Dim txt
 
Set txt = FSO.OpenTextFile(Server.MapPath(“Arquivo.txt”))
Do While txt.AtendOfStream <> True
    Response.Write(txt.ReadLine)
Loop
txt.Close
 

 

:: ASP.NET
1
2
3
 
Dim reader As New StreamReader(Server.MapPath(“Arquivo.txt”))
Dim conteudo As String = reader.ReadToEnd
Response.Write(conteudo)
 

Observações Importantes: Como nos exemplos acima utilizamos como Base de Dados o SQL Server 2000, deve se importar o Namespace System.Data.SqlClient. Ja para utilizar as classes para manipulação de arquivos, deve se importar o Namespace System.IO (Somente para os exemplos escritos em ASP.NET). Abaixo a sintaxe para a Importação:

1
2
 
Imports System.Data.SqlClient
Imports System.IO
 

Conclusão: Como vimos o ASP.NET nos fornece uma facilidade muito grande. Utilizando ainda o Visual Studio .NET como ferramenta de desenvolvimento, as coisas ficam ainda mais fáceis, visto que temos Wizards, Intellisense, entre outras ferramentas que proporcionam um desenvolvimento rápido de aplicações.

Paginando dados com DataList

O grande problema, é que retornamos ao cliente registros indispensáveis para página corrente, o que de certa forma, causa um grande tráfego na rede para no final ser desconsiderado. Sendo assim, retornar todos os registros, e armazenar em uma variável de sessão, também é muito custoso, talvez quando o acesso é mínimo, não se perceba, mas quando a quantidade de usuários requisitando a mesma informação, isso poderá ocasionar sérios problemas de performance.

Tendo este cenário e/ou problema, a solução seria retornarmos da base de dados somente os registros correspondentes a página qual o usuário requerer. Além de diminuir o tráfego de dados na rede, isso nos proporcionará um grande ganho de performance. O artigo mostrará como retornar somente os registros da base de dados qual se enquadram com a página que o usuário requerer. Isso será feito através de uma Stored Procedure, utilizando a tabela Customers da base de dados Northwind como exemplo. Através de um SqlDataReader, recuperamos o result set retornado pela Stored Procedure e populamos o controle DataList.

O primeiro passo e construirmos a Stored Procedure para nos retornar os registros que necessitamos. Com isso, precisamos informar a ela a pagina requerida pelo Usuário, a quantidade de registros à ser exibido por página e também criarmos um parâmetro de OUTPUT para sabermos a quantidade total de registros, que é necessário para efetuar os cálculos no cliente, para que seja possível manipular corretamente a navegação entre as páginas. Abaixo a Stored Procedure responsável por devolver apenas os registros que necessitamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
CREATE PROCEDURE ResgatarClientes
 
    @QtdePagina As Int,
    @PagAtual As Int,
    @TotalClientes As Int OUTPUT
 
    AS
 
    DECLARE @ContactName As Varchar(50)
    DECLARE @City As Varchar(50)
    DECLARE @QtdeInicial As Int
    DECLARE @Contador As Int
 
    SET @QtdeInicial = 0
    SET @Contador = 0
 
    SET NOCOUNT ON
 
    CREATE TABLE #ClientesTemp
    (
        ContactName Varchar(50)
        City Varchar(50)
    )
 
    DECLARE curPaginacaoClientes CURSOR FAST_FORWARD FOR
        SELECT ContactName, City FROM Customers ORDER BY ContactNameASC
 
    OPEN curPaginacaoClientes
    FETCH NEXT FROM curPaginacaoClientes
        INTO @ContactName, @City
 
        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF @QtdeInicial >= (@PagAtual * @QtdePagina) – @QtdePagina
            BEGIN
                INSERT INTO #ClientesTemp VALUES(@ContactName, @City)
                SET @Contador = @Contador + 1
 
                IF @Contador >= @QtdePagina
                    BREAK
            END
            SET @QtdeInicial = @QtdeInicial + 1
 
            FETCH NEXT FROM curPaginacaoClientes
               INTO @ContactName, @City
        END
 
    CLOSE curPaginacaoClientes
    DEALLOCATE curPaginacaoClientes
 
    SELECT ContactName, City FROM #ClientesTemp
 
    DROP TABLE #ClientesTemp
 
    SET NOCOUNT OFF
 
    SET @TotalClientes = (SELECT COUNT(CustomerID) FROM Customers)
GO
 
Código 1 – Stored Procedure “ResgataClientes”.

Como vemos no código acima, a Stored Procedure recebe dois parâmetros que é a página requisitada pelo Usuário e a quantidade de registros por página. Além disso, como dito anteriormente, existe um parâmetro de OUTPUT chamado @TotalClientes que e responsável por retornar a quantidade de Clientes para que seja possível efetuar os cálculos e assim exibindo corretamente a navegação da paginação.

Podemos ver também que é criado uma tabela temporária na linha 19, chamada #ClientesTemp, que é utilizada posteriormente, sendo populada com os registros necessários. Depois disso é criado um Cursor na linha 25 e através dele percorremos a tabela Customers e preenchemos a tabela temporária, anteriormente criada. Feito isso, fechamos o Cursor e o retiramos da memória, e retornamos ao cliente o resultado de um SELECT efetuado nesta tabela temporária na linha 51 e depois apagamos esta tabela (linha 53). E finalmente, apenas atribuimos ao parâmetro de saída a quantidade de registros da tabela Customers na linha 57.

Ainda é possível testá-la no Query Analyser, através do seguinte código:

1
2
3
 
DECLARE @TotalRegistros As Int
EXECUTE ResgatarClientes 10, [N], @TotalClientes = @TotalRegistros OUTPUT
PRINT @TotalRegistros
 
Código 2 – Testando a Stored Procedure “ResgataClientes” no Query Analyser.

Como vemos no código acima, o número 10 é a quantidade de registros por página e o [N] refere-se a página que o cliente está requerendo.

Feito isso, o próximo passo é partir para a aplicação ASP.NET, que irá utilizar esta Stored Procedure para popular e paginar os dados em um controle do tipo DataList. Devemos apenas arrastar em nosso WebForm o DataList e quatro controles do tipo LinkButton, que serão responsáveis pela navegação do usuário. Vamos incluir em nosso WebForm um Data Member que será responsável por armazenar a quantidade de registros por páginas:

1
 
Private _totalRegistrosPagina As Integer = 10
 
Código 3 – Definindo através de um Data Member a quantidade de registros por página.

Logo, temos que criar um procedimento que será responsável por popular o DataList. Esta função se chamará CarregaGrid, e terá como parâmetro um valor inteiro representando a página que o usuário está requerendo. Vejamos abaixo o código deste procedimento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
Private Sub CarregaGrid(ByVal paginaAtual As Integer)
    Dim conn As New SqlConnection(“CONNECTION_STRING”)
    Dim dr As SqlDataReader
    Dim cmd As New SqlCommand(“ResgatarClientes”, conn)
    cmd.CommandType = CommandType.StoredProcedure
 
    Dim paramQtdeRegistroPagina As SqlParameter
    paramQtdeRegistroPagina = New SqlParameter(“@QtdePagina”, SqlDbType.Int)
    paramQtdeRegistroPagina.Value = Me._totalRegistrosPagina
    cmd.Parameters.Add(paramQtdeRegistroPagina)
 
    Dim paramPaginaAtual As SqlParameter
    paramPaginaAtual = New SqlParameter(“@PagAtual”, SqlDbType.Int)
    paramPaginaAtual.Value = paginaAtual
    cmd.Parameters.Add(paramPaginaAtual)
 
    Dim paramTotalRegistros As SqlParameter
    paramTotalRegistros = New SqlParameter(“@TotalClientes”, SqlDbType.Int)
    paramTotalRegistros.Direction = ParameterDirection.Output
    cmd.Parameters.Add(paramTotalRegistros)
 
    Try
        conn.Open()
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        If dr.HasRows() Then
            With Me.dtlDados
                .DataSource = dr
                .DataBind()
            End With
            Me.lblPaginaCorrente.Text = paginaAtual
        End If
    Catch ex As Exception
        Response.Write(ex.ToString)
    Finally
        If Not (dr Is Nothing) Then
            dr.Close()
        End If
        Call Me.ControlePaginacao(cmd.Parameters(“@TotalClientes”).Value)
    End Try
End Sub
 
Código 4 – Procedimento CarregaGrid().

Analisando o código acima, criamos os parâmetros referente à quantidade de registros por página e a página requerida pelo Usuário e também definimos o parâmetro de OUTPUT chamado @TotalClientes, qual retorna a quantidade total de registros. Depois disso, verificamos se é retornado algum registro através da propriedade HasRows(), que retorna True, caso encontrado algum registro, e com isso populamos o DataList com este DataReader, e depois de fechado o DataReader, recuperamos o valor do parâmetro OUTPUT e invocamos o procedimento ControlePaginacao, que é responsável por exibir a quantidade de páginas e a página atual para o Usuário.

O procedimento ControlePaginacao recebe como parâmetro a quantidade total de Clientes, e baseado nisso, exibe a quantidade total de páginas e a página atual em que o Usuário se encontra:

1
2
3
4
5
6
7
 
Private Sub ControlePaginacao(ByVal totalClientes As Integer)
    If (totalClientes Mod Me._totalRegistrosPagina) = 0 Then
        Me.lblTotal.Text = totalClientes / Me._totalRegistrosPagina
    Else
        Me.lblTotal.Text = Convert.ToInt32((totalClientes / Me._totalRegistrosPagina) + 1)
    End If
End Sub
 
Código 5 – Procedimento ControlePaginacao.

Agora, no evento Page_Load do WebForm, devemos chamar o procedimento CarregaGrid, passando como parâmetro o número 1, que refere-se a primeira página, lembrando que devemos chamar este procedimento quando não for PostBack. O código abaixo ilustra isso:

1
2
3
4
5
6
 
Private Sub Page_Load(…) Handles MyBase.Load
    If Not Page.IsPostBack Then
        Call Me.CarregaGrid(1)
        Call Me.Navegacao(1)
    End If
End Sub
 
Código 6 – Evento Page_Load do WebForm.

Ainda temos mais um procedimento para criar, chamado Navegacao, procedimento qual se encarrega de habilitar/desabilitar os botões de navegação da paginação. Este procedimento também é baseado na página atual que está sendo exibida. Vejamos abaixo o código deste procedimento na íntegra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
Private Sub Page_Load(ByVal paginaAtual As Integer)
    If paginaAtual = 1 Then
        With Me
            .lnkAnterior.Enabled = False
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = False
            .lnkUltimaPagina.Enabled = True
        End With
    ElseIf paginaAtual = Me.lblTotal.Text AndAlso paginaAtual > 1 Then
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = False
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = False
        End With
    Else
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = True
        End With
    End If
End Sub
 
Código 7 – Procedimento Navegacao.

Depois disso, nosso controle ficará semelhante à imagem abaixo:

Figura 1 – Controle DataList já com os controles de Navegação pelas páginas.

Mas ainda resta codificarmos os eventos Click() dos LinkButton responsáveis pela navegação das páginas. Temos quatro LinkButtons com as seguintes funcionalidades:

  • < – Primeira página.
  • << – Página anterior.
  • >> – Próxima página.
  • > – Última página.
1
2
3
4
 
Private Sub lnkPrimeiraPagina_Click(…) Handles lnkPrimeiraPagina.Click
    Call Me.CarregaGrid(1)
    Call Me.Navegacao(1)
End Sub
 
Código 8 – Procedimento que retorna à primeira página.

 

1
2
3
4
 
Private Sub lnkUltimaPagina_Click(…) Handles lnkUltimaPagina.Click
    Call Me.CarregaGrid(Convert.ToInt32(Me.lblTotal.Text))
    Call Me.Navegacao(Convert.ToInt32(Me.lblTotal.Text))
End Sub
 
Código 9 – Procedimento que vai para a última página.

 

1
2
3
4
5
 
Private Sub lnkAnterior_Click(…) Handles lnkAnterior.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) – 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 10 – Procedimento que retorna à página anterior.

 

1
2
3
4
5
 
Private Sub lnkProxima_Click(…) Handles lnkProxima.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) + 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 11 – Procedimento vai para a página posterior.

Conclusão: Vimos neste artigo como resgatar os dados da base de dados através de uma Stored Procedure, mas limitando os dados da página a ser exibida para proporcionar performance, retornando os dados para uma aplicação ASP.NET, e populando um controle DataList, controlando e exibindo a paginação.

PaginandoDadosStoredProcedure.zip (22.51 kb)

Guia Inicial do NHibernate

O que é o NHibernate

NHibernate é uma biblioteca (Framework) baseada em .NET para persistir os objetos para bases de dados relacionais. Baseado em uma ferramenta de persistência de dados do Java, chamado Hibernate, o NHibernate tem a finalidade de persistir os objetos .NET em uma base de dados relacional subjacente. Isso facilita muito ao invés de escrever códigos SQL dentro e fora da base de dados, pois o NHibernate gera o código SQL necessário, certificando-se que os tipos e o valores são corretamente criados.

Por que este Guia

Todas as pessoas que já trabalharam com o Hibernate, não sentirão grandes dificuldades em utilizar o NHibernate no mundo .NET. Como os projetos são bastante similares, poderá utilizar a documentação do Hibernate e basear-se nela para aplicar na utilização do NHibernate.

Este artigo é tem a finalidade de mostrar os primeiros passos para a utilização do NHibernate. Cobrirá como persistir um objeto simples em uma tabela.

O Processo de Desenvolvimento

Brevemente o NHibernate terá ferramentas para ajudar na geração do schema da tabela, gerando e atualizando assim os arquivos de mapeamentos. Entretanto, estamos assumindo que não temos estas ferramentas e sendo assim, teremos que criar o arquivo de mapeamento (XML) entre a Classe .NET e a Tabela da Base de Dados manualmente. Abaixo os passos para o desenvolvimento:

  • 1. Criar a Tabela na Base de Dados.
  • 2. Criar a Classe .NET.
  • 3. Criar o Arquivo de Mapeamento.
  • 4. Criar o Arquivo de Configuração do NHibernate.
  • 5. Usar a API do NHibernate.

Passo 1: Escrevendo o SQL

O exemplo é algo bem simples. Considere que estamos desenvolvendo um subsistema básico de gerenciamento de usuários para um Web Site qualquer. O tabela chamará usuários (users) e estaremos assumindo que a Base de Dados a ser utilizada chama-se NHibernate:

1
2
3
4
5
6
7
8
9
10
11
12
 
USE NHibernate
GO
 
    CREATE TABLE users (
        LogonID nvarchar(20) NOT NULL default ‘0’,
        Name nvarchar(40) default NULL,
        Password nvarchar(20) default NULL,
        EmailAddress nvarchar(40) default NULL,
        LastLogon datetime default NULL,
        PRIMARY KEY (LogonID)
GO
)
 

Passo 2: Criando a Classe .NET

Necessitamos criar uma classe com as propriedades que desejamos persistir na Base de Dados. NHibernate utiliza Reflection para resgatar e atribuir os valores as propriedades dos objetos que queremos persistir. Veja abaixo uma classe simples que pode ser persistida utilizando NHibernate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
using System;
 
namespace CS
{
    public class User
    {
        private string id;
        private string userName;
        private string password;
        private string emailAddress;
        private DateTime lastLogon;
 
        public User(){}
 
        private string Id
        {
            get { return id; }
            set { id = value; }
        }
 
        private string UserName
        {
            get { return userName; }
            set { userName = value; }
        }
 
        private string Password
        {
            get { return password; }
            set { password = value; }
        }
 
        private string EmailAddress
        {
            get { return emailAddress; }
            set { emailAddress = value; }
        }
 
        private DateTime LastLogon
        {
            get { return lastLogon; }
            set { lastLogon = value; }
        }
    }
}
 

No exemplo acima, as propriedades e o construtor é definido como públicos, mas isso não é uma exigência para o NHibernate, podendo utilizar propriedades definidas como public, protected, internal ou mesmo private para persistir os dados.

Passo 3: Escrevendo o Arquivo de Mapeamento

Com a tabela criada na Base de Dados e a nossa Classe .NET também escrita, ainda necessitamos uma maneira de dizer ao NHibernate quais as propriedades da Classe .NET que receberá as informações das colunas da tabela da Base de Dados. Isto é realizado através de um arquivo de mapeamento, escrito em formato XML, tendo cada classe seu respectivo arquivo XML de mapeamento.

Para que o sistema funcione corretamente, você deve nomear o arquivo de mapeamento com o mesmo nome da classe, ficando da seguinte forma: “Objeto.hbm.xml”, e no nosso caso: “User.hbm.xml”. Além disso, é necessário colocá-lo no mesmo diretório da classe, pois com isso o NHibernate fará as coisas com mais facilidade. Abaixo um exemplo do arquivo de mapeamento:

1
2
3
4
5
6
7
8
9
10
11
12
 
<?xml version=”1.0″ encoding=”utf-8″ ?>
<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.0″>
    <class name=”CS.User, CS” table=”users”>
        <id name=”Id” column=”LogonId” type=”String” length=”20″>
            <generator class=”assigned” />
        </id>
        <property name=”UserName” column= “Name” type=”String” length=”40″/>
        <property name=”Password” type=”String” length=”20″/>
        <property name=”EmailAddress” type=”String” length=”40″/>
        <property name=”LastLogon” type=”DateTime”/>
    </class>
</hibernate-mapping>
 

Analisando o código acima, o que mais nos chama a atenção são as tags class e table, onde definimos o nome da Classe e o nome da Tabela da Base de Dados de onde será recuperado e/ou inserido os dados. No caso de nosso exemplo, estamos mapeando os dados da tabela “users” para a classe “User”.

Logo mais abaixo temos as propriedades que compõem nosso objeto. Internamento o NHibernate varre este arquivo recuperando os atributos “name”, que correspondem as propriedades da nossa Classe User. É recuperado também o atributo “column”, que se refere a coluna correspondente na Base de Dados, lembrando que este atributo é opcional, e quando ocultado o NHibernate assume que o nome da coluna na Base de Dados é o mesmo da Propriedade.

A tag Id é a responsável por ser a chave identificadora do objeto/registro, onde mapeamos a propriedade (name) para a coluna da Base de Dados (column). No nosso exemplo, geramos as nossas próprias chaves, não necessitando que a Base de Dados gere automaticamente, mas isso é perfeitamente possível. Para saber um pouco mais sobre chaves, poderá consultar a documentação do NHibernate.

Observação: Se você estiver utilizando Visual Studio .NET, certifique-se que ao compilar o projeto a propriedade Build Action dos arquivos XML de mapeamento – que no nosso caso chama-se “User.hbm.xml” – está definido como “Embedded Resource”, para que o arquivo XML faça parte do Assembly como Resource. Isso facilita porque não há a necessidade de distribuir os arquivos XML de mapeamento juntos com a aplicação, mas claro, a desvantagem é que se mudar o arquivo de mapeamento, a aplicação deverá ser recompilada.

Passo 4: Criando o Arquivo de de Configuração para a Base de Dados

Ainda falta dizermos ao NHibernate onde ele deverá ir buscar e persistir os dados. A maneira mais fácil e simples é criando uma seção de configuração dentro do arquivo de configuração da aplicação (Web.Config ou App.Config). Isto é equivalente a usar as propriedades de configuração do NHibernate. Abaixo veremos como criar a seção de configuração dentro do arquivo App.Config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
    <configSections>
        <section
             name=”nhibernate”
             type=”System.Configuration.NameValueSectionHandler, System,
             Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089″ />
    </configSections>
 
    <nhibernate>
    <add
        key=”hibernate.connection.provider”
        value=”NHibernate.Connection.DriverConnectionProvider”
    />
    <add
        key=”hibernate.dialect”
        value=”NHibernate.Dialect.MsSql2000Dialect”
    />
    <add
        key=”hibernate.connection.driver_class”
        value=”NHibernate.Driver.SqlClientDriver”
    />
    <add
        key=”hibernate.connection.connection_string”
        value=”CONNECTION_STRING”
    />
    </nhibernate>
</configuration>
 

No código acima, definimos o SqlClient como Provider para acesso à Base de Dados SQL Server 2000. A ConnectionString foi ocultada apenas para não confundir o leitor, tendo que ser definida com os dados de acesso do servidor de Banco de Dados que estará servindo a aplicação.

Veja não existe nenhuma informação sobre a configuração do log4net. NHibernate usa log4net para registrar o que está acontecendo internamente. Em uma aplicação em produção é recomendável configurarar o log4net e ajustar NHibernate ao nível apropriado do registro para seu cenário.

Passo 5: Utilizando o NHibernate

Até agora fizemos o trabalho árduo. Se tudo ocorreu como esperamos, até o momento temos:

  • Arquivo User.cs – Classe .NET do nosso objeto.
  • Arquivo User.hbm.xml – Arquivo XML de mapeamento.
  • app.Config – Arquivo de Configuração da aplicação.
  • SQL Server – A Tabela “users” criada.

Abaixo os passos que devemos seguir para utilizar o NHibernate para recuperar e inserir os dados na Base de Dados:

  • 1. – Criar o Objeto de Configuração.
  • 2. – Informar ao Objeto de Configuração os tipos de Objeto que deseja persistir.
  • 3. – Criar uma sessão com a Base de Dados.
  • 4. – Carregar, Salvar e Consultar seus objetos.
  • 5. – Fechar ou Flush() na sessão com a Base de Dados.

Abaixo veremos como utilizar o NHibernate:

Inicialmente devemos criar o objeto de configuração do NHibernate que é responsável e tem o conhecimento sobre todos os mapeamentos que existem entre os objetos do nosso sistema e a Base de Dados.

1
2
 
Configuration cfg = new Configuration();
cfg.AddAssembly(“CS”);
 

O objeto de Configuração recupera através do Assembly todos os arquivos que terminam com “.hbm.xml” qual o utilizará para efetuar as manipulações. Existem outras formas de definir e carregar os arquivos de mapeamentos, mas esta é a forma mais simples.

O objeto de ISession representa uma conexão com a sua Base de Dados e o ITransaction representa uma transação controlada também pelo NHibernate.

1
2
3
 
ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
ITransaction transaction = session.BeginTransaction();
 

Depois das configurações realizadas, nos resta definitivamente inserir, carregar e consultar a Base de Dados através do NHibernate:

1
2
3
4
5
6
7
8
9
10
11
 
User newUser = new User();
newUser.Id = “joe_cool”;
newUser.UserName = “Joseph Cool”;
newUser.Password = “abc123”;
newUser.EmailAddress = “joe@cool.com”;
newUser.LastLogon = DateTime.Now;
 
session.Save(newUser);
 
transaction.Commit();
session.Close();
 

Como podemos ver no código acima, um novo objeto do tipo User é criado, definimos as suas propriedades e depois o passamos para o método Save(…) do NHibernate, que baseando-se no arquivo XML de mapeamento correspondente, faz a persistência do objeto de forma “mágica” na nossa Base de Dados.

Para recuperar um objeto da Base de Dados, utilize o método Load, passando o ID do usuário para carregarmos o objeto e assim manipulá-lo. Exemplo:

1
2
3
4
5
6
 
session = factory.OpenSession();
 
User joeCool = (User)session.Load(typeof(User), “joe_cool”);
 
joeCool.EmailAddress = “tt@tt.com”;
session.Flush();
 

Depois de recuperado o Usuario com o Id “joe_cool” da Base de Dados, alteramos o E-Mail do mesmo para “tt@tt.com” e invocamos o método Flush() da Session para persistir/devolver os dados atualizados na Base de Dados.

Podemos também recuperar uma lista de objetos da nossa Base de Dados através do NHibernate. Utilizamos a Interface IList para isto, qual encontra-se dentro do Namespace System.Collections. Um exemplo simples seria algo como:

1
2
3
4
5
6
 
session = factory.OpenSession();
 
IList userList = session.CreateCriteria(typeof(User)).List();
 
foreach(User user in userList)
    Console.WriteLine(user.Id + ” último login em ” + user.LastLogon);
 

CONCLUSÃO: Bem, como vimos neste artigo, a utilização de um OR/M (Object Relational/Mapping) como o NHibernate diminui e muito o grande espaço que existe entre as tabelas de um Banco de Dados relacional e os objetos de uma aplicação. É ótimo para quando se trabalha com uma aplicação fortemente Orientada à Objetos.

Agradecimentos: Gostaria de agradecer ao meu amigo Mike Doerfler, que gentilmente cedeu o artigo (A Quick Start Guide to NHibernate), para que o conteúdo do artigo escrito por ele, seja adaptado e traduzido para a língua portuguesa.

Referências:

Disparando o Evento SelectedIndexChanged do DropDownList

Claro que somente isso não era/é necessário. A necessidade de utilizarmos DropDownList dentro do DataGrid é muito grande, o que exige um pouco de atenção para poder populá-lo. Mas nesse caso a dificuldade não é tão grande. O problema começa a aparecer quando há a necessidade de termos dois DropDownLists dentro deste DataGrid, mas um deles dependendo da seleção do primeiro, e baseado nisso popular este segundo DropDownList. Um cenário bastante conhecido: a exibição dos Clientes dentro deste DataGrid, visualizando a cidade e estado de residência deste Cliente, que ao clicar em editar, deve-se exibir dois DropDownList contendo o Estados e os Municípios que devem ser populados de acordo com o Estado selecionado.

Tendo este cenário, este artigo explicará como construir um DataGrid onde dentro dele, quando editarmos um determinado registro, a linha em edição deverá mostrar os DropDownLists (Estado e Município, respectivamente), onde ao selecionar o Estado, o segundo DropDownList deverá ser populado com as cidades referentes aquele Estado.

Depois de criado uma Aplicação do tipo ASP.NET Web Application, você deve adicionar um DataGrid ao seu WebForm. Com isso, vá até o Property Builder e desmarque a opção: “Create columns automatically at run time”. Com isso, basta adicionarmos o campos a serem exibidos no DataGrid e juntamente os botões de Editar e Cancelar. Finalmente você terá o teu DataGrid próximo à Figura 1 (abaixo):

Figura 1DataGrid já formatado.

Depois de definido as colunas que serão apresentadas no DataGrid, devemos formatar agora o modo de edição do mesmo. Para isso, clique com botão direito do mouse em cima do DataGrid, e na opção Edit Template, selecione a coluna Estado. Com o Template em edição, você adiciona um DropDownList no EditItemTemplate chamado “cboEstado”. Repita os passos anteriores para a coluna Cidade. A Figura 2 (abaixo) ilustra o processo:

Figura 2 – Configurando o EditItemTemplate.

Com o design do DataGrid pronto, resta agora começarmos a codificar o WebForm para popular o DataGrid, mas inicialmente vou chamar a atenção para o código abaixo:

1
2
3
4
5
6
 
Public Class _Default
 
    Private _estado As String
    Private _cidade As String
 
End Class
 
Código 1 – Membros da Classe.

Como podemos ver, é criado estes dois Data Members que serão utilizados posteriormente para quando o Usuário desejar editar o registro, ficar armazenado nestes membros o Estado e Cidade do registro à ser editado, para que seja possível após a carga nos DropDownLists, posicionar os Items de acordo com a Cidade e Estado atual do Cliente.

O método abaixo (CarregaGrid()) é utilizado para preencher o DataGrid no evento Load do WebForm. Está densvinculado, pois será necessário chamarmos em diversos locais. Vejamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
Private Sub Page_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
 
    If Not Page.IsPostBack Then
        Call Me.CarregaGrid()
    End If
End Sub
 
Private Sub CarregaGrid()
    Dim conn As New SqlConnection(“CONNECTION_STRING”)
    Dim cmd As New SqlCommand(“SELECT * FROM [User] ORDER BY Nome ASC”, conn)
    Try
        conn.Open()
        With Me.dg
            .DataSource = cmd.ExecuteReader()
            .DataBind()
        End With
    Catch ex As Exception
        Response.Write(ex.ToString)
    Finally
        If Not conn.State = ConnectionState.Closed Then
            conn.Close()
        End If
    End Try
End Sub
 
Código 2 – Método para carregar o DataGrid.

Como vemos acima, no evento Load do WebForm, chamamos a função CarregaGrid() quando não for um PostBack. Utilizando o SqlDataReader, resgatamos os registros da tabela “Users” e popularmos o DataGrid. Como já definimos as colunas a serem apresentadas, a exibição é controlada pelo DataGrid.

Com o DataGrid já preenchido, devemos codificar os eventos EditCommand e CancelCommand do DataGrid, para que quando o Usuário optar por editar uma determinada linha/registro do DataGrid, puder transformá-la, colocando a disposição os DropDownLists de Estado e Cidade. Abaixo o código para isso:

1
2
3
4
5
6
7
8
 
Private Sub dg_EditCommand(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.EditCommand
 
    Me._cidade = DirectCast(e.Item.FindControl(“Label1”), Label).Text
    Me._estado = DirectCast(e.Item.FindControl(“Label2”), Label).Text
    Me.dg.EditItemIndex = e.Item.ItemIndex
    Call Me.CarregaGrid()
End Sub
 
Código 3 – Evento EditCommand do DataGrid.

Vemos que no evento EditCommand, qual ocorre sempre que o Usuário desejar editar algum registro do DataGrid, armazenamos nos nossos Data Members (falado acima) os valores atuais do Estado e da Cidade do Cliente, que estão armazenados nos Labels. Abaixo o evento CancelCommand do DataGrid, necessário para quando o Usuário desejar cancelar a edição o DataGrid voltar à sua posição inicial:

1
2
3
4
5
6
7
 
Private Sub dg_CancelCommand(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
    Handles dg.CancelCommand
 
    Me.dg.EditItemIndex = –1
    Call Me.CarregaGrid()
End Sub
 
Código 4 – Evento CancelCommand do DataGrid.

Depois dessas funcionalidades codificadas, temos que criar os métodos que serão responsáveis por popular os DropDownLists. Veremos abaixo o método CarregaEstado() que retorna um ArrayList contendo os Estados que serão inseridos no DropDownList Estado dentro do DataGrid:

1
2
3
4
5
6
7
8
9
 
Private Function CarregaEstado() As ArrayList
    Dim arr As New ArrayList
    With arr
        .Add(String.Empty)
        .Add(“SP”)
        .Add(“MT”)
    End With
    Return arr
End Function
 
Código 5 – Método para carregar o DropDownList Estado.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
Private Sub PopulaCidades(ByVal drop As DropDownList, _
    ByVal cidadeAtual As String, ByVal estado As String)
 
    Select Case estado
        Case “SP”
            With drop.Items
                .Add(“Valinhos”)
                .Add(“São Paulo”)
                .Add(“Campinas”)
            End With
        Case “MT”
            With drop.Items
                .Add(“Rondonópolis”)
                .Add(“Cuiabá”)
                .Add(“Várzea Grande”)
            End With
    End Select
    drop.SelectedIndex = drop.Items.IndexOf(drop.Items.FindByText(cidadeAtual))
End Sub
 
Código 6 – Método para carregar o DropDownList Cidade.

O método PopulaCidades(…) acima, recebe por parâmetro o DropDownList que será carregado com as cidades, a cidade atual para que possamos selecionar (marcarmos) a mesma dentro do DropDownList depois de carregado e finalmente o estado para poder fazer a busca de acordo com a seleção do Usuário.

Agora será necessário codificarmos dois eventos do DataGrid: ItemDataBound e ItemCreated. O evento ItemCreated é disparado quando um controle é criado no DataGrid. Já o evento ItemDataBound é disparado logo após que um Item é inserido no cliente. Utilizaremos o evento ItemCreated para quando o DataGrid estiver com algum Item sendo editado, o mesmo possa atribuir ao DropDownList de Estado uma função para ser disparada quando ocorrer o evento SelectedIndexChanged do mesmo. Vejamos abaixo como ficará este evento:

1
2
3
4
5
6
7
8
9
10
11
12
 
Private Sub dg_ItemCreated(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.ItemCreated
 
    If e.Item.ItemType = ListItemType.EditItem Then
        With DirectCast(e.Item.FindControl(“cboEstado”), DropDownList)
            .DataSource = .CarregaEstado()
            .DataBind()
        End With
        AddHandler DirectCast(e.Item.FindControl(“cboEstado”), DropDownList).SelectedIndexChanged, _
        AddressOf Me.CarregaCidade
    End If
End Sub
 
Código 7 – Evento ItemCreated do DataGrid.

Como vemos no evento ItemCreated logo acima, ao encontrar o DropDownList de Estado, já o populamos com o retorno da função CarregaEstado(), e em seguida utilizamos o AddHandler para que quando o evento SelectedIndexChanged deste DropDownList for disparado, executar a função chamada: CarregaCidade(…). Esta função deverá ter obrigatoriamente a mesma assinatura do evento SelectedIndexChanged. Veremos abaixo ela em detalhes:

1
2
3
4
5
6
7
 
Private Sub CarregaCidade(ByVal sender As Object, ByVal e As EventArgs)
    Dim drop As DropDownList = DirectCast(sender, DropDownList)
    Dim dgi As DataGridItem = drop.Parent.Parent
    Dim drop2 As DropDownList = DirectCast(dgi.FindControl(“cboCidade”), DropDownList)
    drop2.Items.Clear()
    Call Me.PopulaCidades(drop2, drop2.SelectedValue, drop.SelectedValue)
End Sub
 
Código 8 – Método que será disparado quando o DropDownList Estado for alterado.

Analisando o código acima, criamos três objetos: drop, dgi e drop2. O drop resgata a referência do objeto que como parâmetro através do sender. Já o dgi, recuperamos a referência do controle pai do drop na hierarquia de controles da página. Com isso, conseguimos saber em qual Item do DataGrid ele se encontra. E finalmente, como temos o Item do DataGrid, basta utilizarmos o método FindControl para popularmos o DropDownList com as cidades.

Para finalizar, apenas resta codificarmos o evento ItemDataBound do DataGrid qual utilizaremos para quando o Usuário desejar editar algum Item, os DropDownLists de Estado e Cidade já vieram populados de acordo com registro atual do Cliente na Base de Dados, ou seja, se o Cliente pertencer ao Estado de “SP”, o DropDownList de Cidade já deverá conter as cidades pertencentes à este Estado.

Depois de todos estes passos, o resultado será:

Figura 3 – Ao clicar em Editar, os DropDownLists já aparecem carregados corretamente.

 

Figura 4 – Repare que a Cidade e Estado estão “marcados” de acordo com o Registro atual.

 

Figura 5 – Ao selecionar o Estado, o DropDownList é carregado de acordo com o Estado selecionado.

Conclusão: Vemos que o WebControl DataGrid nos fornece uma grande facilidade no desenvolvimento. Neste caso, utilizando DropDownLists e executando seu o evento SelectedIndexChanged precisamos codificar algumas linhas, mas nada complexo. Vimos neste artigo, um cenário bastante comum em nosso “dia-a-dia”, ficando aqui explicado como implementá-lo.

DataGridDropDown.zip (21.17 kb)