C# - Cadastro de Alunos com foto (XML)


Nem sempre você vai precisar de um banco de dados para guardar informações.

Os bancos de dados relacionais são a melhor opção quando o objetivo é armazenar e recuperar informações mas apresentam diversos problemas.

Se o seu caso não requer a utilização de um banco de dados considere armazenar informações em arquivos XML.

As perspectivas do armazenamento de dados no formato XML são surpreendentes e até mesmo os Data WareHouses já estão armazenando informações no formato XML.

Um data warehouse (ou armazém de dados, ou depósito de dados no Brasil) é um sistema de computação utilizado para armazenar informações relativas às atividades de uma organização em bancos de dados, de forma consolidada. O desenho da base de dados favorece os relatórios, a análise de grandes volumes de dados e a obtenção de informações estratégicas que podem facilitar a tomada de decisão. (http://pt.wikipedia.org/wiki/Data_Warehouse)

Se pensarmos que a plataforma .NET oferece diversos recursos para que possamos tratar informações no formato XML de forma rápida e descomplicada temos ai um motivo a mais para pensarmos na utilização do formato XML quando realmente indicado.

Neste artigo eu vou mostrar como criar uma aplicação usando a linguagem C# que realiza o gerenciamento de informações sobre alunos , incluindo a foto, persistindo e recuperando as informações de um arquivo XML.

É uma aplicação simples mas meu objetivo é mostrar o potencial que tem este recurso na plataforma .NET.

No exemplo deste artigo eu vou armazenar as seguintes informações sobre alunos:

Irei utilizar o arquivo Alunos.xml para armazenar as informações dos alunos. Este arquivo possui a seguinte estrutura:

<?xml version="1.0" standalone="yes"?>
<alunos>
  <aluno>
    <codigo>10</codigo>
    <nome>Jimmi Hendrix</nome>
    <curso>Musica</curso>
    <mensalidade>3500</mensalidade>
    <foto>10)hendrix.jpg</foto>
  </aluno>
</alunos>

As fotos dos alunos serão armazenadas em uma pasta do projeto chamada Dados juntamente com o arquivo xml. Para evitar que existam nomes de fotos duplicadas (este é um dos problemas de usar esta solução) eu vou sempre concatenar o código do aluno mais o caractere cerquilha (#) com o nome da foto, dessa forma sempre teremos um nome único para a foto.

Para criar o projeto deste artigo eu vou usar o Visual C# 2008 Express Edition e antes de iniciar o projeto vou mostrar a aparência que terá a nossa aplicação na figura abaixo:

Agora vamos ao que interessa...

Criando a aplicação Windows Forms no Vsual C#  2008 Express Edition

Abra o Visual C# 2008 Express e crie um novo projeto do tipo Windows Forms Application no menu File->New Project -> Windows Forms Application com o nome CadastroAlunos;

No formulário form1.cs vamos incluir os controles a partir da ToolBox conforme o leiaute da figura abaixo:

  • 1 DataGridView - gdvAlunos
  • 4 TextBox : txtCodigo, txtNome, txtCurso, txtMensalidade, picFoto
  • 11 Buttons assim designados:

1- Buttons para movimentação dos registros:

  • btnPrimeiro
  • btnAnterior
  • btnProximo
  • btnUltimo

2- Botões para operações de manutenção de dados:

  • btnInlcuir
  • btnProcurar
  • btnAtualizar
  • btnDeletar
  • btnLimpar
  • btnCarregaXML
  • btnSair
  • btnLocalizarFoto
  • 1 Contrrole PictureBox - picFoto

Além disso vamos usar dois controles OpenFileDialog: ofd1 e ofd2.

Após incluir os controles acima e definir o nome de cada um conforme indicado, defina os controles conforme o leiaute acima;

A seguir vamos definir os namespaces usados no projeto no início do formulário form1.cs;

using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualBasic;
using System.IO;

Feito isso vamos definir as variáveis que serão usadas no projeto:

//define variáveis usadas no projeto
DataSet ds;
string fcaminho;
string fdiretorio;
string pcaminho;
string pnome;
string pdestino;
int reg = 0;
DataRow linharegistro;

Vou começar definindo o código do botão de comando Carregar Arquivo XML.

Ao clicar no botão será aberta uma janela de diálogo OpenFileDialog para que seja possível selecionar o arquivo XML que desejamos carregar e exibir no controle DataGridView - gdvAlunos; O código é visto abaixo:

  private void btnCarregaXML_Click(object sender, EventArgs e)
        { 
            try
            {    
                ofd1.Filter = "xml|*.xml|all files|*.*";
                DialogResult res = ofd1.ShowDialog();
                if (res == DialogResult.OK)
                {
                    gdvAlunos.DataSource = null;
                    btnLimpar.PerformClick();
                    fcaminho = ofd1.FileName;
                    ds = new DataSet();
                    ds.ReadXml(fcaminho);               
                    //definindo a chave primaria a fim de procurar o registro usando o método find
                    ds.Tables[0].Constraints.Add("pk_codigo", ds.Tables[0].Columns[0], true);
                    gdvAlunos.DataSource = ds.Tables[0];
                    fdiretorio = fcaminho.Substring(0, fcaminho.LastIndexOf("\\") + 1);
                    mostrarDados();
                }
            }
            catch(Exception ex)
            { MessageBox.Show("Informação inválida : " + ex.Message, "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); }
        }

Se um arquivo for selecionado então faremos o seguinte:

- limpamos os controles do formulário: btnLimpar.PerformClick();

- Obtemos o caminho e nome do arquivo selecionado: fcaminho = ofd1.FileName;

- Criamos um dataset e usando o método ReadXml(fcaminho) lemos o conteúdo do arquivo XML para o dataset;

- Definimos uma chave primaria na tabela a fim de procurar o registro usando o método Find;

O método Find da coleção Rows retorna um objeto DataRow, e, neste caso, uma única linha e não um array de linhas.
Este método precisa que você defina a propriedade chave primária (Primary Key) antes de usá-lo. Se você não fizer isso vai obter uma exceção.

- Chamamos a rotina mostrarDados() para exibir os dados no DataGridView;

Vejamos a seguir o código da rotina mostrarDados():

   void mostrarDados()
        {  
            if (ds.Tables[0].Rows.Count > 0)
            {  
                picFoto.Image = null;
                txtCodigo.Text = ds.Tables[0].Rows[reg][0].ToString();
                txtNome.Text = ds.Tables[0].Rows[reg][1].ToString();
                txtCurso.Text = ds.Tables[0].Rows[reg][2].ToString();
                txtMensalidade.Text = ds.Tables[0].Rows[reg][3].ToString();
                picFoto.ImageLocation = fdiretorio + ds.Tables[0].Rows[reg][4].ToString();
            }
            else
                MessageBox.Show("Não existem registros.","Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        }

Este código verifica se existem linhas na tabela : if (ds.Tables[0].Rows.Count > 0)

Em caso positivo exibe os dados nos controles do formulário. Estamos usando um dataset não tipado onde temos que definir a posição do registro na tabela do dataset da seguinte forma:

ds.Tables[0].Rows[reg][0].ToString();

A rotina mostrarDados() não retorna nada por isso o modificador void. Ela será usada sempre que desejamos exibir informações nos controles do formulário.

Vejamos agora o código do botão Incluir que deverá incluir um novo aluno no arquivo XML:

   private void btnIncluir_Click(object sender, EventArgs e)
        {
            linharegistro = null;
            linharegistro = ds.Tables[0].Rows.Find(txtCodigo.Text);
            if (linharegistro == null)
            {
                //atribui os valores dos controles ao datarow
                linharegistro = ds.Tables[0].NewRow();
                linharegistro[0] = txtCodigo.Text;
                linharegistro[1] = txtNome.Text;
                linharegistro[2] = txtCurso.Text;
                linharegistro[3] = txtMensalidade.Text;

                salvaFoto();    
                linharegistro[4] = pnome;
                //inclui uma linha na tabela
                ds.Tables[0].Rows.Add(linharegistro);
                reg = ds.Tables[0].Rows.IndexOf(linharegistro);
                //salva dados no arquivo xml
                ds.WriteXml(fcaminho);
                MessageBox.Show("Registro incluído com sucesso.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            }
            else
            MessageBox.Show("Registro já existe.O código deve ser único.","Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        }

Verificamos se o registro já existe usando o método Find: linharegistro = ds.Tables[0].Rows.Find(txtCodigo.Text);

Em caso positivo criamos uma nova linha(NewRow) e atribuímos os valores informados no TextBox à nova linha;

Chamamos a rotina SalvaFoto() e incluímos a nova linha na tabela e em seguida gravamos os dados no arquivo XML usando o método ds.WriteXml();

A rotina SalvaFoto() tem seu código exibido a seguir:

    void salvaFoto()
        {
            //Procurando o nome da foto
            //salvando na pasta do arquivo xml com nome unico (codigo+nome_foto)
            pcaminho = picFoto.ImageLocation;
            pnome = txtCodigo.Text + "#" + (pcaminho.Substring(pcaminho.LastIndexOf('\\') + 1));//(codigo + nome da foto)
            pdestino = fdiretorio + pnome;
            picFoto.Image.Save(pdestino);//salva imagem no disco
        }

Neste código atribuímos o caminho da foto a variável pcaminho e montamos o nome da foto com o código do aluno mais o caractere # e o nome da foto;

Montamos o diretório de destino e salvamos a foto no disco.

No botão Procurar temos o código que localiza um registro e exibe as informações no formulário:

   private void btnProcurar_Click(object sender, EventArgs e)
        {
                    
            int n = Convert.ToInt32(Interaction.InputBox("Informe o código do aluno :", "Procurar", "10", 200, 200));
            //procurando registros usando o método find
            linharegistro = null;
            linharegistro = ds.Tables[0].Rows.Find(n);
            if (linharegistro != null)
            {   //preenche os controles do formulário
                reg = ds.Tables[0].Rows.IndexOf(linharegistro);
                txtCodigo.Text = linharegistro[0].ToString();
                txtNome.Text = linharegistro[1].ToString();
                txtCurso.Text = linharegistro[2].ToString();
                txtMensalidade.Text = linharegistro[3].ToString();
                picFoto.ImageLocation = fdiretorio + linharegistro[4];
            }
            else
                MessageBox.Show("registro não localizado.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            
        }

Solicitamos o código do aluno usando o InputBox e novamente usamos o método Find para localizar o registro

O código do botão Atualizar que altera os dados do arquivo XML:

      private void btnAtualizar_Click(object sender, EventArgs e)
        {
            //procurando registros usando o método find
            DataRow linharegistro = ds.Tables[0].Rows.Find(txtCodigo.Text);
            if (linharegistro!= null)
            {
                reg = ds.Tables[0].Rows.IndexOf(linharegistro);
                //atribui os valores dos controles aos campos da tabela
                ds.Tables[0].Rows[reg][0] = txtCodigo.Text;
                ds.Tables[0].Rows[reg][1] = txtNome.Text;
                ds.Tables[0].Rows[reg][2] = txtCurso.Text;
                ds.Tables[0].Rows[reg][3] = txtMensalidade.Text;

                File.Delete(fdiretorio + linharegistro[4]);
                salvaFoto();

                ds.Tables[0].Rows[reg][4] = pnome;
                //grava no arquivo xml
                ds.WriteXml(fcaminho);
                MessageBox.Show("registro atualizado", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            }
            else
                MessageBox.Show("Não existe registro de aluno com este código.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        }

Localizamos o item usando o método Find e atribuímos os valores informados nas caixas de texto as linhas da tabela , salvamos a foto e gravamos as alterações no arquivo XML.

A rotina para excluir uma linha do arquivo é vista no código a seguir:

  private void btnDeletar_Click(object sender, EventArgs e)
        {
            //procurando registros usando o método find
            DataRow linharegistro = ds.Tables[0].Rows.Find(txtCodigo.Text);
            if (linharegistro!= null)
            {
                File.Delete(fdiretorio + linharegistro[4]);
                ds.Tables[0].Rows.Remove(linharegistro);   
                ds.WriteXml(ofd1.FileName);
                MessageBox.Show("Registro deletado.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                reg = 0;
                mostrarDados();
            }
            else
                MessageBox.Show("Não existe registro de aluno com este código.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
        }

Localizamos o item usando o método Find e usando método Remove excluímos a linha da tabela.

O código de cada um dos botões de navegação é mostrado a seguir:

   private void btnPrimeiro_Click(object sender, EventArgs e)
        {
            reg = 0;
            mostrarDados();
        }

        private void btnAnterior_Click(object sender, EventArgs e)
        {
            if (reg > 0)
            {
                reg--;
                mostrarDados();
            }
            else
            { MessageBox.Show("Primeiro Registro."); }
        }

        private void btnProximo_Click(object sender, EventArgs e)
        {
            if (reg < ds.Tables[0].Rows.Count - 1)
            {
                reg++;
                mostrarDados();
            }
            else
            { MessageBox.Show("Último Registro."); }
        }

        private void btnUltimo_Click(object sender, EventArgs e)
        {
            reg = ds.Tables[0].Rows.Count - 1;
            mostrarDados();
        }

Verificamos a posição do registro e usamos a rotina mostraDados para exibir os dados atuais.

O código do botão Limpar é dado a seguir:

        private void btnLimpar_Click(object sender, EventArgs e)
        {
            //limpa controles TextBox do formulário e o picturebox
            txtCodigo.Text = txtNome.Text = txtCurso.Text = txtMensalidade.Text = "";
            picFoto.Image = null;
        }

Também incluímos o código abaixo no evento CellClick do DataGridView;

     private void gdvAlunos_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                //obtem o valor da primeira célula do grid que é o código do aluno
                int codigo = Convert.ToInt32(gdvAlunos.CurrentRow.Cells[0].Value);
                linharegistro = ds.Tables[0].Rows.Find(codigo);
                if (linharegistro != null)
                {   //preenche os controles do formulário
                    reg = ds.Tables[0].Rows.IndexOf(linharegistro);
                    txtCodigo.Text = linharegistro[0].ToString();
                    txtNome.Text = linharegistro[1].ToString();
                    txtCurso.Text = linharegistro[2].ToString();
                    txtMensalidade.Text = linharegistro[3].ToString();
                    picFoto.ImageLocation = fdiretorio + linharegistro[4];
                }
                else
                    MessageBox.Show("registro não localizado.", "Aviso", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            }
            catch
            { }
        }

dessa forma quando uma linha do grid for clicada obtemos os valores da linha e exibimos no formulário.

Para encerrar temos o código do botão que encerra a aplicação

  private void btnSair_Click(object sender, EventArgs e)
        {
            DialogResult resultado = MessageBox.Show("Deseja Encerrar a aplicação?",
            "Sair", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            if (resultado == DialogResult.Yes)
                Application.Exit();
        }

Com isso mostramos que podemos ter informações armazenadas em arquivos XML e que podemos tratá-la de forma dinâmica e funcional com os recursos da linguagem C#.

Simples, simples assim

O projeto completo com os fontes abertos está no  Super DVD .NET.

Eu sei é apenas XML, mas eu gosto...

Referências:

José Carlos Macoratti