C# - Cadastro de Alunos com foto no SQL Server II
Na primeira parte deste artigo eu criei o projeto e defini o seu escopo, em seguida criei o banco de dados e as stored procedures usadas no projeto e por fim criei a interface da aplicação. Pois bem falta agora definir o código que vai realmente fazer tudo funcionar.
Lembrando que pretendemos realizar as seguintes tarefas:
As tarefas são simples e em diversos artigos eu já mostrei como realizar cada uma delas, mas resolvi criar este projeto simples para ajudar quem esta começando na linguagem C#,
Eu estou usando os seguintes recursos :
A interface do projeto foi definida no formulário fom1.cs e possui o seguinte leiaute:(leiaute ou lay-out ?)
Definindo o código do projeto
O que vamos fazer agora é usar os eventos dos controles dos formulários como Click, KeyPress, Change,etc. para inserir o código respectivo referente à tarefa que desejamos executar.
É uma boa prática fazer isso ?
Não, não é.
Sempre que criarmos um projeto, devemos separar as responsabilidades, e, uma das primeiras coisas que devemos fazer é definir a arquitetura da nossa aplicação.
O ideal é separar as responsabilidades em camadas de forma a que elas sejam independentes uma das outras com o objetivo de facilitar a manutenção e poder reutilizar o código.
Quando colocamos na interface, como vamos fazer neste exemplo, código que acessa os dados usando referências a objetos ADO .NET estamos misturando na interface responsabilidades que não deveriam estar presentes. A interface deveria saber somente de responsabilidades da interface como exibição e formatação de dados.
O acesso aos dados deveria estar em uma camada distinta e somente ela seria responsável por esta tarefa. Da mesma forma nela não devem existir tarefas relacionadas com a interface como uso de controles para exibir informações , etc.
Como o projeto é bem simples e estamos tratando dele para o nível iniciante não vou me preocupar em definir camadas e vou usar os eventos dos controles do formulário para colocar o código que vai fazer todo o serviço que desejamos.
A primeira tarefa é definir os namespaces no formulário.
Podemos
dizer que os Namespaces organizam os objetos em um
assembly ; assim , um assembly podem conter um ou mais
namespaces , e estes namespaces pode conter um ou mais
namespaces. Desta forma os Namespaces evitam a
ambiguitdade e organizam referências quando são usados
grande grupos de objetos como as librarys de classes. Um assembly é unidade primária de construção da plataforma .NET , ou seja , é o tijolo da plataforma sobre o qual tudo o mais se apoia. Um assembly pode ser reutilizado e é auto-descritivo de maneira a permitir que um runtime .NET possa gerenciar plenamente a aplicação. |
Comece sempre por este item , pois é ele que vai definir quais classes você vai poder acessar e se durante a definição do código precisarmos acessar outros recursos basta incluir o novo namespace.
A seguir temos os namespaces que iremos usar:
using System;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing;
using Microsoft.VisualBasic;
Após isso vamos definir as variáveis que serão visíveis em todo o formulário. Lembre-se que se definirmos uma variável no interior de um método dependendo do seu escopo ela não será visível em outro método ou evento no projeto.
A seguir temos as variáveis que iremos usar no projeto:
SqlConnection con;
SqlCommand cmd;
SqlDataAdapter adapter;
DataSet ds;
int linhaNumero = 0;
MemoryStream ms;
byte[] foto_array;
As 4 primeiras variáveis vão tratar de acesso e tratamento dos dados e as demais da navegação e da conversão da foto em dados binários.
O primeiro evento que iremos usar é o evento que é executado quando abrirmos o formulário form1.cs, o evento Load;
private void Form1_Load(object sender, EventArgs e) { string strcon = @"Data Source=.\SQLEXPRESS;AttachDbFilename=c:\dados\Escola.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True"; con = new SqlConnection(strcon); carregaDados(); exibe_Dados(); } |
Como ele é um dos primeiros eventos que antes do formulário ser aberto vamos definir neste evento o seguinte:
A string de conexão usa o arquivo SQL Server Escola.mdf que esta na pasta c:\dados.Não é uma boa prática definir a string de conexão no código pois dificulta a manutenção e pode levar a erros.
O ideal seria colocá-la no arquivo de configuração App.Config e obtê-la usando a classe ConfigurationManager, mas para não complicar as coisas eu defini a string de conexão na variável strcon;
Usamos em seguida esta string de conexão para abrir uma conexão com o banco de dados.
O código da rotina carregaDados() é dado abaixo:
void carregaDados() { cmd = new SqlCommand("getAlunos", con); cmd.CommandType = CommandType.StoredProcedure; adapter = new SqlDataAdapter(cmd); adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; ds = new DataSet(); adapter.Fill(ds, "Alunos"); } |
Nesta rotina estamos usando a stored procedure getAlunos que seleciona os alunos da tabela Alunos e preenchendo um DataSet chamado Alunos deixando-o pronto para ser usado.
A rotina exibeDados possui o seguinte código:
void exibe_Dados() { if (ds.Tables[0].Rows.Count > 0) { txtCodigo.Text = ds.Tables[0].Rows[linhaNumero][0].ToString(); txtNome.Text = ds.Tables[0].Rows[linhaNumero][1].ToString(); txtCurso.Text = ds.Tables[0].Rows[linhaNumero][2].ToString(); txtMensalidade.Text = String.Format("{0:C}",ds.Tables[0].Rows[linhaNumero][3].ToString()); picFoto.Image = null; if (ds.Tables[0].Rows[linhaNumero][4] != System.DBNull.Value) { foto_array = (byte[])ds.Tables[0].Rows[linhaNumero][4]; MemoryStream ms = new MemoryStream(foto_array); picFoto.Image = Image.FromStream(ms); } } else { MessageBox.Show("Não há registros na tabela"); } } |
O código acima verifica se o dataset possui linhas e exibe os dados do registro correspondente nos controles de formulário.
Verificamos também se a imagem do aluno atribuída é nula e caso isso não ocorra definimos um array de bytes com os dados binários da imagem e convertemos esses dados em uma imagem para ser exibida no controle PicutreBox.
Para escolher uma imagem a ser atribuída como foto ao aluno temos o botão Escolher e no seu evento Click incluímos o seguinte código:
private void ProcurarFoto_Click(object sender, EventArgs e) { oFd1.Filter = "jpeg|*.jpg|bmp|*.bmp|all files|*.*"; DialogResult res = oFd1.ShowDialog(); if (res == DialogResult.OK) { picFoto.Image = Image.FromFile(oFd1.FileName); } } |
Ao clicar no botão escolar o controle OpenFileDialog(Ofd1) irá abrir uma caixa de diálogo para que uma imagem seja escolhida. Ao fazer isso a imagem do arquivo selecionado é exibido no controle PictureBox - picFoto.
Para procurar um aluno já cadastro temos o botão Procurar cujo código do evento Click é o seguinte:
private void Procurar_Click(object sender, EventArgs e) { try { int n = Convert.ToInt32(Interaction.InputBox("Informe o código do Aluno:", "Procurar", "1", 450, 400)); DataRow drow; drow = ds.Tables[0].Rows.Find(n); if (drow != null) { linhaNumero = ds.Tables[0].Rows.IndexOf(drow); txtCodigo.Text = drow[0].ToString(); txtNome.Text = drow[1].ToString(); txtCurso.Text = drow[2].ToString(); txtMensalidade.Text = drow[3].ToString(); picFoto.Image = null; if (drow[4] != System.DBNull.Value) { foto_array = (byte[])drow[4]; MemoryStream ms = new MemoryStream(foto_array); picFoto.Image = Image.FromStream(ms); } } else MessageBox.Show("Registro não localizado."); } catch { MessageBox.Show("Dados inválidos."); } } |
Neste código usamos o método InputBox para solicitar que seja informado o código do aluno.
A seguir usamos o método Find para localizar o registro na tabela e exibimos as informações no formulário.
Agora eu vou definir o código que permite navegar pelos registros e que será inserido no evento Click dos botões de comando
Abaixo temos o código dos 4 botões de comando para realizar a navegação:
private void Primeiro_Click(object sender, EventArgs e) { linhaNumero = 0; exibe_Dados(); MessageBox.Show("Primeiro registro"); } private void Anterior_Click(object sender, EventArgs e) { if (linhaNumero > 0) { linhaNumero--; exibe_Dados(); } else MessageBox.Show("Primeiro registro"); } private void Proximo_Click(object sender, EventArgs e) { if (linhaNumero < ds.Tables[0].Rows.Count - 1) { linhaNumero++; exibe_Dados(); } else MessageBox.Show("Úlitmo registro"); } private void Ultimo_Click(object sender, EventArgs e) { linhaNumero = ds.Tables[0].Rows.Count - 1; exibe_Dados(); MessageBox.Show("Úlitmo registro"); } |
A navegação é baseada na variável linhaNumero que representa o índice do registro atual da tabela e na rotina exibe_Dados() que exibe os registros do índice atual representando por linhaNumero.
Vejamos agora o código de cada um dos botões que realizam as tarefas de incluir, atualizar e deletar registros da tabela:
1- Botão Novo
O botão Novo apenas limpa os controles do formulário e põe o foco no controle txtNome que é caixa de texto para inserir o nome do aluno, dessa forma basta o usuário digitar as informações e clicar no botão Incluir;
private void btnNovo_Click(object sender, EventArgs e) { txtCodigo.Text = txtNome.Text = txtCurso.Text = txtMensalidade.Text = ""; picFoto.Image = null; txtNome.Focus(); } |
2- Botão Incluir
No evento Click do botão Incluir temos o código que usa stored procedure inserir_alunos , passa os parâmetros referente aos dados que serão incluídos , converte a foto para o formato binário, inclui e exibe os registros no formulário;
private void Inserir_Click(object sender, EventArgs e) { cmd = new SqlCommand("inserir_Alunos", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@nome", txtNome.Text); cmd.Parameters.AddWithValue("@curso", txtCurso.Text); cmd.Parameters.AddWithValue("@mensalidade", txtMensalidade.Text); converterFoto(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("registro inserido com sucesso."); carregaDados(); } else MessageBox.Show("Erro ao inserir registro."); } |
3- Botão Atualizar
No evento Click do botão Atualizar repetimos os mesmos passos usando a stored procedure atualiza_alunos;
private void Atualizar_Click(object sender, EventArgs e) { cmd = new SqlCommand("atualiza_Alunos", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@id", txtCodigo.Text); cmd.Parameters.AddWithValue("@nome", txtNome.Text); cmd.Parameters.AddWithValue("@curso", txtCurso.Text); cmd.Parameters.AddWithValue("@mensalidade", txtMensalidade.Text); converterFoto(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Registro atualizado"); carregaDados(); } else MessageBox.Show("Erro ao atualizar dados."); } |
4- Botão Deletar
No evento Click do botão Deletar usamos a propriedade DialogResult que representa o valor que é retornado do formulário obtido na janela de diálogo apresentada. No caso estamos solicitando a confirmação para excluir o registro.
A seguir usamos a stored procedure exclui_alunos e passamos como parâmetro o código do aluno informado na caixa de texto txtCodigo;
private void Excluir_Click(object sender, EventArgs e) { DialogResult resultado = MessageBox.Show("Confirma exclusão deste Aluno ?", "Confirma Exclusão", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if(resultado == DialogResult.Yes) { cmd = new SqlCommand("exclui_Alunos", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@id", Convert.ToInt32(txtCodigo.Text)); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Registro Excluído"); carregaDados(); linhaNumero = 0; exibe_Dados(); }else{ MessageBox.Show("Erro ao excluir registro."); } } } |
Após excluir um registro carregamos os dados novamente.
Estamos usando o evento KeyPress do controle TextBox - txtMensalidade, para permitir que somente valores numéricos sejam informados neste controle:
private void txtMensalidade_KeyPress(object sender, KeyPressEventArgs e) { if (!char.IsNumber(e.KeyChar) && !(e.KeyChar == '.') && !(e.KeyChar == Convert.ToChar(8))) { e.Handled = true; } } |
A rotina ConverteFoto é a responsável por converter a imagem para dados binários antes de gravar no banco de dados:
void converterFoto() { //convertendo a foto para dados binários if (picFoto.Image != null) { ms = new MemoryStream(); picFoto.Image.Save(ms, ImageFormat.Jpeg); byte[] foto_array = new byte[ms.Length]; ms.Position = 0; ms.Read(foto_array, 0, foto_array.Length); cmd.Parameters.AddWithValue("@foto", foto_array); } } |
E assim criamos um projeto usando os recursos da ADO .NET via código e do SQL Server usando a linguagem C#, onde temos todo o código necessário para tratar as informações dos alunos e realizar as operações CRUD (Create,Read, Update e Delete) na tabela Alunos.
Executando o projeto e gravando as informações para um aluno com foto obtemos:
Podemos melhorar o projeto criando a tal camada de acesso a dados e separando o código de acesso a dados da interface. Podemos também implementar um tratamento de erros mais eficaz, e incluir outros recursos. Fique a vontade...
Simples, simples assim...
Para encerrar rei implementar a rotina para imprimir os dados do aluno com foto. Aguarde...
O projeto completo esta no Super DVD .NET
Eu sei é apenas C# mas eu gosto...
Referências: