WPF - Controle de usuários com ADO .NET
O objetivo deste artigo é mostrar como criar uma aplicação WPF básica para gerenciar um cadastro de usuários com login e senha usando os recursos da ADO .NET.
Nossa aplicação deverá acessar um banco de dados SQL Server 2008 Express chamado Usuarios, criado no SQL Server Management Studio, que possui a tabela Userdata com a seguinte estrutura:
Estrutura da tabela
Userdata :
onde ID é uma chave primária do tipo Identity. |
O foco é gerenciar o cadastro de usuários realizando as operações CRUD - inclusão, atualização e exclusão de usuários.
Vamos abrir o Visual C# 2010 Express Edition e criar um novo projeto do tipo WPF Application: File -> New Project -> WPF Application;
Informe o nome ControlaUsuarios e clique em OK;
Vamos incluir no projeto um arquivo de configuração para que possamos armazenar a string de conexão com o banco de dados SQL Server.
No menu Project -> Add New Item , selecione o template Application Configuration File, aceite o nome App.Config e clique em Add;
Isso irá criar o arquivo App.Config no projeto. Agora inclua no arquivo o código abaixo que define a string de conexão com o banco de dados usado no projeto:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="conexaoSQLServer" providerName="System.Data.SqlClient" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Usuarios.mdf;Integrated Security=True;User Instance=True;" /> </connectionStrings> </configuration> |
Note que definimos o nome da seção : conexaoSQLServer , o provedor usado: System.Data.SqlClient e a string de conexão usada.
Selecione o arquivo MainWindow1.xaml e a partir da ToolBox vamos incluir nesta janela os seguintes controles:
Defina o leiaute do formulário conforme a figura abaixo:
O código XAML gerado será o seguinte:
<Window x:Class="DatabaseApplication.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Controle de Usuários" Height="373" Width="522" Loaded="Window_Loaded" Background="White"> <Grid Height="336" Width="503" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition Width="141*" /> <ColumnDefinition Width="356*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="136*" /> <RowDefinition Height="198*" /> <RowDefinition Height="2*" /> </Grid.RowDefinitions> <ListView Margin="8,9,68,125" Name="lstvUsuarios" ItemsSource="{Binding}" MinWidth="350" MinHeight="100" Grid.ColumnSpan="2" Grid.RowSpan="2" Background="#BFF3D9D2"> <ListView.View> <GridView> <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Path=ID}"></GridViewColumn> <GridViewColumn Header="Usuário" DisplayMemberBinding="{Binding Path=usuario}"></GridViewColumn> <GridViewColumn Header="Senha" DisplayMemberBinding="{Binding Path=senha}"></GridViewColumn> </GridView> </ListView.View> </ListView> <TextBox Margin="92,81,145,96" Name="txtUsuario" DataContext="{Binding ElementName=lstvUsuarios,Path=SelectedItem}" _ Text="{Binding Path=usuario}" Grid.ColumnSpan="2" Grid.Row="1" Background="#FFEFFAC3" /> <TextBox Height="23" Margin="92,0,145,65" Name="txtSenha" VerticalAlignment="Bottom" DataContext="{Binding ElementName=lstvUsuarios,Path=SelectedItem}" _ Text="{Binding Path=senha}" Grid.ColumnSpan="2" Grid.Row="1" Background="#7DEBE88D" CharacterCasing="Normal" /> <Label Margin="16,81,53,92" Name="label1" Grid.Row="1" Content="Usuário :"></Label> <Label Height="30" Margin="16,0,53,56" Name="label2" VerticalAlignment="Bottom" Grid.Row="1" Content="Senha :"></Label> <Button Height="26" Margin="16,0,51,23.5" Name="btnIncluir" VerticalAlignment="Bottom" Click="btnIncluir_Click" Grid.Row="1" Content="Incluir"></Button> <Button Height="26" Margin="102,0,0,23.5" Name="btnAtualizar" VerticalAlignment="Bottom" Click="btnAtualizar_Click" HorizontalAlignment="Left" Width="75" _ Grid.ColumnSpan="2" Grid.Row="1" Content="Atualizar"></Button> <Button Height="26" Margin="51,0,0,23.5" Name="btnDeletar" VerticalAlignment="Bottom" Click="btnDeletar_Click" Grid.Column="1" HorizontalAlignment="Left" _ Width="75" Grid.Row="1" Content="Deletar"></Button> <Button Height="27.5" Margin="136,0,145,22.75" Name="btnLimpar" VerticalAlignment="Bottom" Click="btnLimpar_Click" Grid.Column="1" Grid.Row="1" Content="Limpar"></Button> </Grid> </Window> |
Observe que estou usando os recursos do DataBinding do WPF para vincular os dados da tabela nos controles do formulário.
Essa é a interface da nossa aplicação e através dela iremos realizar o gerenciamento dos usuários existentes na tabela Userdata;
- Ao carregar o projeto o controle ListView deverá exibir os usuários cadastrados;
- Ao selecionar uma linha do controle ListView as informações
de nome de usuário e senha deverão ser exibidos nas caixas de
texto do formulário;
- No evento Click de cada um dos botões teremos
o código que irá realizar as operações CRUD para manutenção
dos dados;
Para tornar nossa pequena aplicação mais aderente as boas práticas iremos criar uma classe chamada Acesso que será responsável por realizar as operações CRUD usando os recursos da ADO .NET;
Dessa forma teremos uma classe responsável pelo acesso e persistência dos dados na aplicação separando assim as responsabilidades de acesso a dados da intereface.
No menu Project, selecione Add Class , informe o nome Acesso.cs e clique em Add;
As declarações de uso de namespaces definidos na classe são:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
O namespace adotado para esta classe será: DatabaseApplication
Devemos também incluir uma referência ao namespace System.Configuration no projeto.
No menu Project -> Add Reference, selecione a Aba .NET na janela Add Reference e selecione : System.Configuration e clique em OK;
Vamos agora definir os seguintes métodos nesta classe:
A seguir irei descrever cada um dos métodos :
1- getConexaoSQLServer() - obtém e retorna um a conexão com o SQL Server a partir do arquivo App.Config.
/// <summary> /// Obtem uma conexão com o banco de dados /// </summary> /// <returns></returns> public static SqlConnection getConexaoSQLServer() { string strCon = GetConnectionStringByNome("conexaoSQLServer"); if (strCon == null) throw new Exception("String de conexão não localizada."); SqlConnection con = new SqlConnection(strCon); return con; } |
2- closeConexaoSQLServer() - Fecha uma conexão com o SQL server.
/// <summary> /// Fecha a conexao /// </summary> /// <param name="conexao"></param> public static void closeConexaoSQLServer(SqlConnection conexao) { if (conexao.State == ConnectionState.Open) conexao.Close(); } |
3- Insert(usuario,senha) - Inclui um novo usuário e senha.
/// <summary> /// inclui um novo usuario /// </summary> /// <param name="usuario"></param> /// <param name="senha"></param> public static void Insert(string usuario, string senha) { if (!verificaUsuario(usuario)) { throw new Exception("Usuário ja existe."); } SqlConnection con = Acesso.getConexaoSQLServer(); try { con.Open(); SqlCommand comm = new SqlCommand("insert into userdata(usuario,senha) values(@usuario,@senha)", con); comm.Parameters.AddWithValue("@usuario", usuario); comm.Parameters.AddWithValue("@senha", GerarHash(senha)); comm.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { closeConexaoSQLServer(con); } } |
4- verificaUsuario(user) - Verifica se o nome do usuário informado já esta cadastrado.
/// <summary> /// Verifica se um usuário ja esta cadastrado /// </summary> /// <param name="user"></param> /// <returns></returns> private static bool verificaUsuario(string user) { SqlDataReader dr = null; SqlConnection con = getConexaoSQLServer(); string sql = "Select * from userdata where usuario='" + user +"'"; try { con.Open(); SqlCommand cmd = new SqlCommand( sql, con); dr = cmd.ExecuteReader(); if (dr.HasRows) { return false; } else { return true; } } catch (Exception ex) { throw ex; } } |
5- Update(id,usuario,senha) - Atualiza os dados de um usuário.
/// <summary> /// atualiza um registro selecionado /// </summary> /// <param name="id"></param> /// <param name="usuario"></param> /// <param name="senha"></param> public static void Update(int id,string usuario, string senha) { SqlConnection con = getConexaoSQLServer(); try { con.Open(); SqlCommand comm = new SqlCommand("update userdata set usuario=@usuario,senha=@senha where id=@id", con); comm.Parameters.AddWithValue("@id", id); comm.Parameters.AddWithValue("@usuario", usuario); comm.Parameters.AddWithValue("@senha", GerarHash(senha)); comm.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { closeConexaoSQLServer(con); } } |
6- Delete(id) - Exclui um usuário existente com base no id do usuário.
/// <summary> /// deleta um registro selecionado /// </summary> /// <param name="id"></param> public static void Delete(int id) { SqlConnection con = getConexaoSQLServer(); try { con.Open(); SqlCommand comm = new SqlCommand("delete from userdata where id=@id", con); comm.Parameters.AddWithValue("@id", id); comm.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { closeConexaoSQLServer(con); } } |
7- getTabela() - Retorna um DataTable contendo todos os usuários cadastrados.
/// <summary> /// retorna um datatable com todos os usuarios /// </summary> /// <returns></returns> public static DataTable getTabela() { SqlConnection con = getConexaoSQLServer(); try { con.Open(); SqlCommand comm = new SqlCommand("Select * from userdata", con); DataTable dt = new DataTable(); SqlDataAdapter da = new SqlDataAdapter(comm); da.Fill(dt); return dt; } catch(Exception ex) { throw ex; } finally { closeConexaoSQLServer(con); } } |
8- GeraHash() - Gera o hash para a senha do usuário.
/// <summary> /// gera o hash /// </summary> /// <param name="Valor"></param> /// <returns></returns> public static string GerarHash(string Valor) { System.Security.Cryptography.SHA1Managed Sha = new System.Security.Cryptography.SHA1Managed(); Sha.ComputeHash(System.Text.Encoding.Default.GetBytes(Valor)); return Convert.ToBase64String(Sha.Hash); } |
Definindo o código da Interface
A seguir veremos o código dos eventos que ocorrem nos controles usados na interface MainWindow1.xaml.
Estaremos usando a classe Acesso e usar os métodos ali definidos para acessar e persistir as informações.
O evento Loaded() irá ser executado quando o formulário for carregado e nele iremos exibir os dados na interface;
private void Window_Loaded(object sender, RoutedEventArgs e) { try { ExibeDados(); } catch (Exception ex) { MessageBox.Show("Erro : " + ex.Message); this.Close(); } } |
No botão incluir temos o código que chama o método Insert da classe Acesso. Primeiro validamos as informações e a seguir incluímos o usuário e exibimos os dados:
private void btnIncluir_Click(object sender, RoutedEventArgs e) { string usuario = txtUsuario.Text; string senha = txtSenha.Text; if (ValidaDados()) { try { Acesso.Insert(usuario, senha); ExibeDados(); } catch (Exception ex) { MessageBox.Show(" Erro : " + ex.Message, "Erro", MessageBoxButton.OK, MessageBoxImage.Error); } } } |
No evento Click do botão Deletar o solicitamos a confirmação e verificamos se existe um usuário selecionado no ListView para obtermos o seu id e usarmos o método Delete() para excluir o usuário;
Para obter o id do usuário selecionado no ListView obtemos um DataRowView que representa um modo de exibição personalizado de um DataRow e a seguir usamos a propriedade Row para obter o DataRow visualizado que no caso é a coluna zero (Row[0]) representando o id do usuário;
private void btnDeletar_Click(object sender, RoutedEventArgs e) { if (MessageBox.Show("Confirma exclusão deste registro ?", "Excluir", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { if (lstvUsuarios.SelectedItems.Count > 0) { DataRowView drv = (DataRowView)lstvUsuarios.SelectedItem; int id = Convert.ToInt32(drv.Row[0].ToString()); try { Acesso.Delete(id); ExibeDados(); } catch (Exception ex) { MessageBox.Show(" Erro : " + ex.Message, "Erro", MessageBoxButton.OK, MessageBoxImage.Error); } } } } |
Para atualizar um usuário temos que selecioná-lo no ListView, validar as informações, obter o seu id no ListView e então usar o método Update();
private void btnAtualizar_Click(object sender, RoutedEventArgs e) { string usuario = txtUsuario.Text; string senha = txtSenha.Text; if (ValidaDados()) { if (lstvUsuarios.SelectedItems.Count > 0) { DataRowView drv = (DataRowView)lstvUsuarios.SelectedItem; int id = Convert.ToInt32(drv.Row[0].ToString()); try { Acesso.Update(id, usuario, senha); ExibeDados(); } catch (Exception ex) { MessageBox.Show(" Erro : " + ex.Message,"Erro",MessageBoxButton.OK,MessageBoxImage.Error); } } } } |
A rotina ExibeDados() usa o método getTabela para obter um DataTable contendo os usuários cadastrados e exibí-los no ListView;
public void ExibeDados() { DataTable dtb = Acesso.getTabela(); lstvUsuarios.DataContext = dtb.DefaultView; } |
No botão Limpar , atribuimos um valor vazio as caixas de texto e colocamos o foco no nome do usuário;
private void btnLimpar_Click(object sender, RoutedEventArgs e) { txtUsuario.Text = ""; txtSenha.Text = ""; txtUsuario.Focus(); } |
A rotina de validação é bem simples e apenas verifica se as informações não estão em branco ou possuem um tamanho menor que 6 caracteres;
private bool ValidaDados() { bool retorno; if (txtSenha.Text == string.Empty || txtSenha.Text.Length < 6 ) { MessageBox.Show("Informe a senha do Usuário com no mínimo seis caracteres.", "Senha", MessageBoxButton.YesNo, MessageBoxImage.Error); txtSenha.Focus(); return false; } else { retorno = true; } if (txtUsuario.Text == string.Empty || txtUsuario.Text.Length < 6) { MessageBox.Show("Informe o nome do Usuário com no mínimo seis caracteres.", "Senha", MessageBoxButton.YesNo, MessageBoxImage.Error); txtSenha.Focus(); return false; } else { retorno = true; } return retorno; } |
Executando o projeto teremos o seguinte resultado:
Sugestões para melhorias no projeto:
Pegue o projeto completo aqui: ControlaUsuarios.zip
Eu sei é apenas WPF, mas eu gosto...
Referências: