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 MattosA 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:
Controle | Propriedade | Valor |
Form1 | Name | Form1 |
Text | Alimentando o TreeView com o OleDbDataReader | |
TreeView | Name | tvwClientes |
Dock | Top | |
ImageList | ImageList1 | |
SelectedImageIndex | 4 | |
Button | Name | cmdCarregarTreeView |
Text | Carregar TreeView | |
StatusBar | Name | StatusBar1 |
Text | Barra de Status | |
OpenFileDialog | Name | OpenFileDialog1 |
ImageList | Name | ImageList1 |
Images | Ver ilustração abaixo |
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:
Índice na Lista | Nome do Arquivo |
0 | PastaFechada.ico |
1 | PastaAberta.ico |
2 | Pedidos.ico |
3 | Detalhes.ico |
4 | ItemSelecionado.ico |
5 | PedidoAberto.ico |
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.
Procedimento de Evento | Implementação |
cmdCarregarTreeView_Click | Este é o principal procedimento deste exemplo. Nele colocaremos o código necessário para estabelecermos a conexão com o Banco de Dados, extrairmos as informações dos Clientes, Pedidos e Detalhes dos Pedidos e finalmente alimentarmos o controle TreeView. |
tvwClientes_AfterCollapse | Este procedimento será utilizado para restaurarmos os ícones originais dos objetos Nodes do controle TreeView toda vez que o usuário colapsar um "nó". |
tvwClientes_AfterExpand | Neste procedimento de evento implementaremos o código necessário para alterarmos os ícones dos objetos Nodes do TreeView toda vez que o usuário expandir um "nó". |
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 SubtvwClientes_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 SubConclusã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.
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET