C# - Exibindo informações do banco de dados com ListView e TreeView


Este artigo mostra como acessar um banco de dados e exibir as informações das tabelas usando os controles ListView e TreeView.

Neste exemplo eu vou acessar um banco de dados Microsoft Access mas o código pode ser facilmente adaptado para acessar outros bancos de dados como SQL Server, MySQL, FireBird, etc.

Este é um artigo para iniciantes e aborda o acesso a dados, a utilização dos controles ListView e TreeView, a utilização do OpenFileDialog.

Para criar o projeto deste artigo eu vou usar o Visual C# 2010 Express Edition (ele é gratuito).

Abra o Visual C# 2010 Express e crie um novo projeto do tipo Windows Forms Application com o nome acessoDados_TreeView;

Em seguida vamos definir a interface com o usuário no formulário form1.vb conforme o leiaute da figura abaixo:

Os componentes usados a partir da ToolBox foram:

O projeto vai funcionar assim:

  1. O usuário seleciona um banco de dados Microsoft Access clicando no botão de comando;
  2. A janela OpenFileDialog será aberta exibindo os arquivos .mdb da pasta c:\dados ; (Defini esta pasta como inicial mas você pode usar outra pasta.)
  3. Após selecionar um banco de dados o seu nome será exibido no TextBox - txtBancoDados e as tabelas serão exibidas no controle TreeView - tvDados;
  4. Ao expandir uma tabela clicando no sinal de (+) ao lado da mesma os campos e os dados da tabela serão exibidos no controle ListView - lvDados;

A seguir temos a imagem mostrando a tela principal do programa exibindo informações para o banco de dados Northwind.mdb nos controles ListView e TreeView;

No código do projeto eu estou usando dois arrays do tipo ArrayList: tabelaArray : para salvar os nomes das tabelas e camposArray - para salvar os nomes dos campos

As rotinas definidas no código são as seguintes:

Nas rotinas GetTabelas e GetCampos estou usando o método GetOleDbSchemaTable para obter informações do esquema do banco de dados.

Para obter o nomes dos campos estou usando OleDbSchemaGuid, e, os nomes dos campos são retornados ordenados (A-Z)

Definindo o código da aplicação

Vamos agora mostrar passo a passo o código das rotinas criadas no projeto para que a aplicação faça o que foi proposto.

-Namespaces usados no projeto:

using System;
using System.Data;
using System.Windows.Forms;
using System.Collections;
using System.Data.OleDb;

Os namespaces System.Data e System.Data.OleDb devem ser usados para termos acesso as classes ADO .NET e ao provedor OleDb para acesso ao Microsoft Access.

O namespace System.Collections é usado para ter acesso a classe ArrayList.

- Variáveis globais definidas logo após a declaração do formulário form1;

private OleDbConnection conexaoBD;
private string arquivoDados;
private ArrayList tabelaArray;
private ArrayList camposArray;

- Código definido no evento Load do formulário form1 da aplicação responsável por inicializar os controles TreeView e ListView;

 private void Form1_Load(object sender, EventArgs e)
 {
            // inicializa o TreeView
            tvDados.ImageList = imageList1;
            // inicializa o ListView
            lvDados.SmallImageList = imageList1;
            lvDados.Clear();
            lvDados.View = View.Details;
            lvDados.LabelEdit = false;
            lvDados.FullRowSelect = true;
            lvDados.GridLines = true;
 }

- Código definido no evento Click do botão para selecionar um arquivo que exibe a janela para seleção do arquivo .mdb;

  private void btnSelecionaBD_Click(object sender, EventArgs e)
   { 
            arquivoDados = selecionaArquivoBD("c:\\dados\\");
            conexaoDados(arquivoDados);
            txtBancoDados.Text = arquivoDados;
  }
Após selecionar o arquivo será aberta a conexão com o mesmo e definido o seu nome na caixa de texto.
- Código da rotina conexaoDados(arquivoDados) ;
   private void conexaoDados(string arquivoDadosBD)
   {
            //define a string de conexão usando o provedor Oledb
            string conexao = @"provider=microsoft.jet.oledb.4.0;Password="""";data source=" + arquivoDadosBD;
            try
            {
                //Inicializa o objeto conexaoBD
                conexaoBD = new OleDbConnection(conexao);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            preencherTreeView();
   }
neste código é chamada a rotina preencherTreeView();
- Código da rotina preencherTreeView()  que obtém informações sobre as tabelas e os campos exibindo-as no controle TreeView;
       private void preencherTreeView()
        {
            tvDados.Nodes.Clear();
            // define o no raiz para o TreeView.
            tvDados.Nodes.Add("Database");
            tvDados.Nodes[0].ImageIndex = 0;
            tvDados.Nodes[0].SelectedImageIndex = 0;
            tvDados.Nodes[0].Tag = "RootDB";

            GetTabelas(conexaoBD);

            // inclui um no tabela
            for (int i = 0; i < tabelaArray.Count; i++)
            {
                tvDados.Nodes[0].Nodes.Add(tabelaArray[i].ToString());
                tvDados.Nodes[0].Nodes[i].Tag = "Tabelas";
                tvDados.Nodes[0].Nodes[i].ImageIndex = 2;
                tvDados.Nodes[0].Nodes[i].SelectedImageIndex = 2;
            }

            // inclui um  no campo
            for (int i = 0; i < tabelaArray.Count; i++)
            {
                GetCampos(conexaoBD, tabelaArray[i].ToString());
                for (int j = 0; j < camposArray.Count; j++)
                {
                    tvDados.Nodes[0].Nodes[i].Nodes.Add(camposArray[j].ToString());
                    tvDados.Nodes[0].Nodes[i].Nodes[j].Tag = "Campos";
                    tvDados.Nodes[0].Nodes[i].Nodes[j].ImageIndex = 4;
                    tvDados.Nodes[0].Nodes[i].Nodes[j].SelectedImageIndex = 4;
                }
            }
        }
Este código usa as rotinas GetTabelas() e GetCampos() para obter informações das tabelas e seus campos.
- Código da rotina GetTabelas() que obtém informação sobre o esquema , no caso o nome das tabelas e preenche o array tabelaArray;
        private void GetTabelas(OleDbConnection conBD)
        {
            try
            {
                //abre a conexão
                conBD.Open();
                //obtem informações do esquema (nome das tabelas do banco de dados)
                DataTable schTable = conBD.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,
                    new Object[] { null, null, null, "TABLE" });

                tabelaArray = new ArrayList();
                //preenche o array com  o nome das tabelas
                foreach (DataRow datRow in schTable.Rows)
                {
                    tabelaArray.Add(datRow["TABLE_NAME"].ToString());
                }
                conBD.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
- Código da rotina GetCampos() que obtém informações sobre os nomes dos campos da tabela e preenche o arraylist camposArray;
    private void GetCampos(OleDbConnection conBD, string tabNode)
        {
            string tabelaNome;
            try
            {
                tabelaNome = tabNode;
                //abre a conexão
                conBD.Open();
                //obtem informações do esquema (nome dos campos da tabela)
                DataTable schTable = conBD.GetOleDbSchemaTable(OleDbSchemaGuid.Columns,
                    new Object[] { null, null, tabelaNome });

                camposArray = new ArrayList();
                //preenche o array com o nome dos campos
                foreach (DataRow datRow in schTable.Rows)
                {
                    camposArray.Add(datRow["COLUMN_NAME"].ToString());
                }
                conBD.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
- Código do evento AfterExpand do controle TreeView que é disparado quando o usuário expande um nó Tabela exibindo os dados no ListView;
       private void tvDados_AfterExpand(object sender, TreeViewEventArgs e)
        {
            string tabelaNome;
            int contadorCampo;

            if (e.Node.Tag.ToString() == "RootDB")
            {
                e.Node.ImageIndex = 1;
                e.Node.SelectedImageIndex = 1;
            }
            else if (e.Node.Tag.ToString() == "Tabelas")
            {
                e.Node.ImageIndex = 3;
                e.Node.SelectedImageIndex = 3;
                contadorCampo = e.Node.GetNodeCount(false);
                // cria o cabeçalho das colunas.
                int n = lvDados.Width;
                double largura = n / contadorCampo ; // largura a coluna
                for (int c = 0; c < contadorCampo; c++)
                {
                    lvDados.Columns.Add(e.Node.Nodes[c].Text, (int)largura, HorizontalAlignment.Left);
                }
                // pega o nome da tabela
                tabelaNome = e.Node.Text;
                PreencherListView(conexaoBD, tabelaNome);
            }
        }
Neste evento é chamada a rotina PreencherListView().
- Código da rotina PreencherListView() que exibe as informações da tabela no controle ListView;
  private void PreencherListView(OleDbConnection conBD, string nomeTabela)
  {
            OleDbCommand cmdBD;
            OleDbDataReader datReader;

            string strCampo;
            
            //define o nome da tabela
            txtTabela.Text = nomeTabela;
            
            //define uma instrução SQL para obter os dados da tabela
            strCampo = "SELECT * FROM [" + nomeTabela + "]";
            
            // Inicializa o objeto command
            cmdBD = new OleDbCommand(strCampo, conBD);
            //abre a conexão e executa o command
            conBD.Open();
            datReader = cmdBD.ExecuteReader();

            // Preenche o ListView
            while (datReader.Read())
            {
                ListViewItem objListItem = new ListViewItem(datReader.GetValue(0).ToString());
                for (int c = 1; c < datReader.FieldCount; c++)
                {
                    objListItem.SubItems.Add(datReader.GetValue(c).ToString());
                }
                objListItem.ImageIndex = 5;
                lvDados.Items.Add(objListItem);
            }
            //fecha o datareader e a conexao
            datReader.Close();
            conBD.Close();
    }
O código do evento AfterCollapse do TreeView que ocorre antes do Nó é recolhido.
   private void tvDados_AfterCollapse(object sender, TreeViewEventArgs e)
   {
            if (e.Node.Tag.ToString() == "RootDB")
            {
                e.Node.ImageIndex = 0;
                e.Node.SelectedImageIndex = 0;
            }
            else if (e.Node.Tag.ToString() == "Tabelas")
            {
                e.Node.ImageIndex = 2;
                e.Node.SelectedImageIndex = 2;
                lvDados.Clear();
            }
  }
O código do evento BeferoExpand do TreeView que ocorre antes que um Nó é expandido;
     private void tvDados_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            lvDados.Clear();
            // expande somente um no
            for (int i = 0; i < tvDados.Nodes[0].GetNodeCount(false); i++)
            {
                tvDados.Nodes[0].Nodes[i].Collapse();
            }
        }  
Finalmente o código do evento Click do item do menu Sair que pergunta ao usuário se ele deseja encerrar:
   private void SairMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Deseja encerrar o programa ?", "Aplicação",MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                Application.Exit();
            }
        }
Eu sei é apenas C# mas eu gosto...
Pegue o projeto completo aqui: acessoDados_TreeView.zip
C# , Simples, simples assim... 
Referências:

José Carlos Macoratti