Desenvolvimento - Visual Basic .NET

TreeView com VB.NET - Alimentando o TreeView com OleDbDataReader do ADO.NET

Neste artigo você aprenderá a alimentar o controle TreeView utilizando informações extraídas do banco de dados Northwind.mdb. Conheça o OleDbDataReader e confira o que mudou no TreeView nesta nova versão do VB.NET.

por Carlos de Mattos



Introdução

A apresentação de dados para o usuário não é uma tarefa muito fácil. Neste artigo, você aprenderá a utilizar o controle TreeView, um dos controles mais versáteis encontrados no Visual Basic, para exibir dados extraídos do arquivo Northwind.mdb (em português). Durante a implementação desta tarefa, você conhecerá e também aprenderá como utilizar outro objeto de acesso à dados do ADO.NET, o OleDbDataReader.

O objetivo principal deste pequeno exemplo é exibir os Clientes, Pedidos e Detalhes dos Pedidos da empresa Northwind Traders, como demonstrado na figura abaixo:


Figura 1: A interface do aplicativo.

Construindo nossa interface

Inicie o Visual Studio .NET e crie uma nova solução baseada no template Windows Application. Informe o nome TreeView para sua nova solução.

Para completarmos nossa interface, precisaremos de cinco controles: TreeView, Button, StatusBar, OpenFileDialog e o ImageList. O objeto de acesso à dados, o OleDbDataReader, será implementado programáticamente. Utilize a tabela abaixo como referência para atualizar algumas propriedades dos controles que utilizaremos:

A propriedade Images do controle ImageList1:

O controle ImageList também sofreu algumas modificações, observe na Figura 2 a nova janela para edição da propriedade Images. Outra mudança positiva para este controle é que o desenvolvedor pode inserir ou remover imagens da lista sem se preocupar se a lista está ou não vinculada a outro controle, isto não era possível no VB6.


Figura 2: A janela "Image Collection Editor"

Preste atenção neste ponto: Como utilizaremos a propriedade ImageIndex das imagens da lista para atribuí-las aos "nós" do TreeView você deve inserí-las na mesma ordem apresentada na tabela abaixo:


Tabela 1: Arquivos de imagem para o controle ImageList1

Escrevendo o código

Para implementarmos as funcionalidades do nosso aplicativo será necessário a criação dos Procedimentos para os seguintes eventos: cmdCarregarTreeView_Click, tvwClientes_AfterCollapse e tvwClientes_AfterExpand.

Tabela 2: Descrição dos Procedimentos de Evento.

O código do botão Carregar TreeView

Como citei anteriormente, este é o principal Procedimento de Evento deste nosso exemplo. Antes que o leitor veja o código fonte deste procedimento, gostaria de esclarecer alguns pontos muito importantes:

Ativando a ampulheta do Windows para indicar processamento em andamento

Lembram-se do código Screen.MousePointer = vbHourGlass? Pois é, ele não existe mais e para você ativar a ampulheta do Windows será necessário incluir a linha seguinte:

Cursor.Current = System.Windows.Forms.Cursors.WaitCursor

O Namespace System.Windows.Forms possui uma coleção de cursores que podem ser acionados a qualquer momento da forma apresentada acima. O objeto Cursor.Current representa o cursor atual e você deve utilizá-lo sempre que desejar exibir um novo cursor no seu aplicativo. O que aconteceu com o App.Path?

Esta é mais uma mudança no VB.NET, o App.Path foi substituído pela propriedade Location que pode ser acessada conforme demonstrado na linha de código abaixo:

System.Reflection.Assembly.GetExecutingAssembly.Location

Esta propriedade armazena o Path completo (incluindo o nome) do arquivo executável da sua aplicação.

Os métodos BeginUpdate e EndUpdate do controle TreeView

Para preservar a performance do seu aplicativo enquanto os itens são adicionados um de cada vez no controle TreeView, você deve utilizar o método BeginUpdate. Este método impede que o controle seja atualizado até que o método EndUpdade seja chamado.

O objeto OleDbDataReader

Este objeto, pertencente ao Namespace System.Data.OleDb, oferece uma forma de leitura dos registros extraídos de um banco de dados. A grosso modo, poderíamos comparar o OleDbDataReader com o antigo objeto Recordset ForwardOnly. Para criar um OleDbDataReader, o desenvolvedor precisa de uma conexão ativa e um objeto Command que será utilizado para extrair os registro do banco de dados. É muito importante registrar que enquando o objeto OleDbDataReader estiver aberto, a conexão utilizada por ele não estará disponível. Isto quer dizer que se você implementar este objeto, deverá criar uma conexão exclusiva para ele e fechá-la após sua utilização. A performance obtida justifica esses detalhes. Lembramos que para bancos de dados SQL Server o desenvolvedor deve utilizar o objeto SqlDataReader que foi concebido para o mesmo fim.

A lógica implementada

Este é um ponto que pode ser analisado e modificado de forma a atender os mais diversos conceitos e técnicas de programação de cada desenvolvedor. Utilizei uma lógica simples que permite a a extração dos dados de forma hierárquica utilizando apenas uma conexão e uma única instrução SQL.

Código do Procedimento cmdCarregarTreeView_Click():

Private Sub cmdCarregarTreeView_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles cmdCarregarTreeView.Click

Dim strCnString As String

Dim strAppPath As String

Dim strDatabasePath As String

Dim cnNorthwind As OleDb.OleDbConnection

Cursor.Current = System.Windows.Forms.Cursors.WaitCursor

StatusBar1.Text = "Aguarde ... Conectando Banco de Dados ... "

strAppPath = Mid(System.Reflection.Assembly.GetExecutingAssembly.Location, 1, _

Len(System.Reflection.Assembly.GetExecutingAssembly.Location) _

- Len("treeview.exe"))

strDatabasePath = strAppPath & "Northwind.mdb"

If Dir(strDatabasePath) = "" Then

With OpenFileDialog1

.DefaultExt = "*.mdb"

.FileName = "Northwind.mdb"

.Filter = "Microsoft Access Databases (*.mdb)|*.mdb|Todos arquivos (*.*)|*.*"

.Title = "Informe a localização do Arquivo Northwind.mdb (em português)"

.ShowDialog()

End With

If Dir(OpenFileDialog1.FileName) = "" Then

MessageBox.Show("Você precisa informar a localização do arquivo "_

Northwind.mdb.", "Banco de Dados não Localizado", MessageBoxButtons.OK, _

MessageBoxIcon.Exclamation)

Else

strDatabasePath = OpenFileDialog1.FileName

End If

End If

"As linhas abaixo constroem a string de conexão com o Northwind

strCnString = "Provider=Microsoft.Jet.OLEDB.4.0;"

strCnString = strCnString & "User ID=Admin;"

strCnString = strCnString & "Password=;"

strCnString = strCnString & "Data Source=" & strDatabasePath

"Criamos uma nova instância da classe OleDbConnection

cnNorthwind = New OleDb.OleDbConnection(strCnString)

"ativamos o tratamento de erros para conectarmos ao banco de dados.

Try

cnNorthwind.Open()

StatusBar1.Text = "Banco de dados conectado com sucesso."

Catch exConnection As System.Exception

MessageBox.Show(exConnection.GetBaseException.ToString, "Erro ao Conectar " _

com o Banco de Dados", MessageBoxButtons.OK, MessageBoxIcon.Error)

End Try

StatusBar1.Text = "Aguarde ... Carregando informações do banco de dados ..."

"Invocamos o método BeginUpdate para iniciarmos a atualização do controle TreeView

"este método permite que todas as modificações no controle sejam feitas e somente

"sejam atualizadas na tela após invocarmos o método EndUpdate.

tvwClientes.BeginUpdate()

tvwClientes.Nodes.Clear()

Dim sqlClientes As String

sqlClientes = "SELECT Clientes.CódigoDoCliente, Clientes.NomeDaEmpresa, " _

& "Pedidos.NúmeroDoPedido, [Detalhes do Pedido].Quantidade, " _

& "Produtos.NomeDoProduto, [Detalhes do Pedido].PreçoUnitário " _

& "FROM Produtos INNER JOIN ((Clientes INNER JOIN Pedidos " _

& "ON Clientes.CódigoDoCliente = Pedidos.CódigoDoCliente) " _

& "INNER JOIN [Detalhes do Pedido] " _

& "ON Pedidos.NúmeroDoPedido=[Detalhes do Pedido].NúmeroDoPedido) " _

& "ON Produtos.CódigoDoProduto=[Detalhes do Pedido].CódigoDoProduto " _

& "ORDER BY Clientes.NomeDaEmpresa, Pedidos.NúmeroDoPedido," _

& "[Detalhes do Pedido].CódigoDoProduto;"

Dim cmdClientes As New OleDb.OleDbCommand(sqlClientes, cnNorthwind)

"Esta é a variável que armazenará o objeto OleDbDataReader

Dim drClientes As OleDb.OleDbDataReader

"Carregaremos o objeto OleDbDataReader com os registros retornados pelo objeto "OleDbCommand. Para isso será necessário invocarmos o método ExecuteReader() do "objeto OleDbCommand.

drClientes = cmdClientes.ExecuteReader()

"Variáveis utilizadas para criação dos "nós" do TreeView

Dim nodeCliente As TreeNode

Dim nodePedido As TreeNode

Dim nodeDetalhe As TreeNode

Dim strClienteAtual As String = ""

Dim intPedidoAtual As Integer

"Iniciamos o loop através dos registros contidos no OleDbDataReader

While drClientes.Read()

"Verificamos se o registro corresponde ao cliente atual

If Not drClientes("CódigoDoCliente") = strClienteAtual Then

nodeCliente = New TreeNode()

With nodeCliente

.ImageIndex = 0

.Tag = "cliente"

.Text = drClientes("NomeDaEmpresa")

End With

"Depois de criado o novo "nó" - adicionaremos-o ao controle TreeView

tvwClientes.Nodes.Add(nodeCliente)

"Atualizamos a variável com o código do cliente atual

strClienteAtual = drClientes("CódigoDoCliente")

End If

"Aqui iniciamos a criação dos "nós" que exibirão os pedidos de cada cliente.

If Not drClientes("NúmeroDoPedido") = intPedidoAtual Then

nodePedido = New TreeNode()

With nodePedido

.ImageIndex = 2

.Tag = "pedido"

.Text = drClientes("NúmeroDoPedido")

End With

"Adicionamos o "nó" do pedido para o cliente atual.

"Observe a hierarquia contida na linha abaixo:

"TreeView.Nodes(<nó do cliente atual>).Nodes.Add(<nó do pedido>)

tvwClientes.Nodes(nodeCliente.Index).Nodes.Add(nodePedido)

"atualizamos a variável para indicar qual é o pedido atual.

intPedidoAtual = drClientes("NúmeroDoPedido")

End If

"finalmente criamos os nós para os detalhes dos pedidos

"como último nível na hierarquia representada os detalhes do pedido não

"necessitam do teste lógico implementado anteriormente para os Clientes e Pedidos

nodeDetalhe = New TreeNode()

"Atualizamos suas propriedades para armazenar o registro com os detalhes do pedido

With nodeDetalhe

.ImageIndex = 3

.Tag = "detalhe"

.Text = drClientes("Quantidade") & " - " & drClientes("NomeDoProduto") & " - " _

& "R$ " & FormatNumber(drClientes("PreçoUnitário"), 2)

End With

"Concluindo, adicionamos os nós dos detalhes ao pedido correspondente.

"TreeView.Nodes(<nó do cliente>).Nodes(<nó do pedido>).Nodes.Add(<nó do detalhe>)

tvwClientes.Nodes(nodeCliente.Index).Nodes(nodePedido.Index).Nodes.Add(nodeDetalhe)

End While

"fechamos o objeto OleDbDataReader

drClientes.Close()

"invocamos o método EndUpdate do controle TreeView para que as atualizações sejam

"apresentadas ao usuário.

tvwClientes.EndUpdate()

"fechamos a conexão com o banco de dados

cnNorthwind.Close()

"notificamos o usuário da conclusão da operação

StatusBar1.Text = "Operação concluída com sucesso."

"restauramos o cursor

Cursor.Current = System.Windows.Forms.Cursors.Default

End Sub

O código dos procedimentos tvwClientes_AfterExpand e tvwClientes_AfterColapse

Este código é bem mais simples, precisaremos apenas de um Select Case para identificar a categoria do objeto Node (Cliente, Pedido ou Detalhe) selecionado para atribuir a imagem correta a ele.

tvwClientes_AfterExpand:

Private Sub tvwClientes_AfterExpand(ByVal sender As Object, ByVal e As _ System.Windows.Forms.TreeViewEventArgs) Handles tvwClientes.AfterExpand

"este é o código para alterarmos os ícones quando o usuário expande os "nós"

Select Case e.Node.Tag

Case "cliente"

e.Node.ImageIndex = 1

Case "pedido"

e.Node.ImageIndex = 5

End Select

End Sub

tvwClientes_AfterColapse:

Private Sub tvwClientes_AfterCollapse(ByVal sender As Object, ByVal e As _ System.Windows.Forms.TreeViewEventArgs) Handles tvwClientes.AfterCollapse

"este é o código para restaurar os ícones quando o usuário colapsar os "nós"

Select Case e.Node.Tag

Case "cliente"

e.Node.ImageIndex = 0

Case "pedido"

e.Node.ImageIndex = 2

Case "detalhe"

e.Node.ImageIndex = 3

End Select

End Sub

Conclusão

Neste artigo você aprendeu como criar programáticamente um objeto OleDbDataReader e como utilizá-lo para alimentar um controle TreeView. O artigo ilustrou outras modificações que encontramos no VB.NET, como por exemplo, a localização do arquivo executável da sua aplicação e o controle dos cursores, que é uma das formas mais utilizadas para notificar o usuário de que algo está acontecendo. Utilize este exemplo como referência e tente implementar outras funcionalidades. Minha sugestão é que você reproduza esse exemplo passo-a-passo para fixar o conteúdo abordado. Espero que tenham gostado. Até a próxima oportunidade.

Carlos de Mattos

Carlos de Mattos - É profissional certificado pela Microsoft desde 1998. Atua como desenvolvedor de soluções customizadas para o mercado corporativo há mais de 10 anos. Foi premiado pela Microsoft como MVP em 2003 e 2004. Tem diversos artigos publicados nas revistas FórumAccess e MSDN Magazine, nos Websites MSDN Online Brasil, Portal DevMedia/MSDN e Linha de Código. Carlos também atuou durante 5 anos junto à Comunidade Acadêmica na região de Sorocaba/SP ministrando palestras e treinamentos junto às Universidades e Colégios Técnicos. Atualmente está em Sorocaba/SP, na WD5 Solutions dedicando-se à implementação de soluções baseadas em tecnologia Microsoft.NET.