quarta-feira, 14 de novembro de 2012

C# - Criando um Componente TextBox personalizado



Muitas vezes necessitamos utilizar um componente diferente ou com alguma funcionalidade a mais em nossas aplicações, na maioria dos casos devemos realizar esta tarefa herdando de um componente principal ou até mesmo o criando do zero, escrevendo-o diretamente da classe “Object”. Podemos manipular suas propriedades e métodos até chegar ao resultado que desejamos. Na linguagem C# isto se torna uma tarefa fácil e prática, sendo que neste artigo vou criar um “TextBox” personalizado contendo validações de CPF, CNPJ e PIS usando o método “OnValidating()”. Reescreverei métodos e propriedades como: “OnLostFocus()”, “OnGotFocus()” e ”ForeColor” para dar uma impressão um pouco mais interessante ao usuário. Será necessário também criar uma classe “Tipo” para trabalharmos com o Tipo de validação necessária. Para esta tarefa achei mais prático utilizar um “combobox” acoplado nas suas propriedades.

Criando o Componente

Inicie o Microsoft Visual Studio e crie um novo projeto como “Class Libary”. (Não se preocupe que disponibilizarei todo o código fonte)
Clique com o botão direito sobre a solução e escolha “Add/New Item...”. Criaremos uma classe do início. Ver Figura 01.


Figura 01: Criar uma classe para o TextBox.

Vou abordar assuntos já mencionados em assuntos anteriores, primeiramente importe algumas bibliotecas úteis ao longo do desenvolvimento.

using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;

System.Windows.Forms: Assembly que contém a classe TextBox.
System.Drawing: Assembly responsável pela troca de cores dos componentes.
System.ComponentModel: Classes responsáveis pela manipulação e conversão de dados dos componentes.
O primeiro passo ao criar uma classe é definir o atributo como “Public”, para podermos visualizá-la em qualquer parte do projeto e logo em seguida usar o recurso de herança para a classe “TextBox”. Defina também o “Constructor” e “Destructor” do componente. Especificamente neste artigo não precisei utilizá-los, mas recomendo sempre a criação do mesmo.

//Herança de Classes
public class TextBoxTheClub: TextBox
{
    //Definindo o Contructor
    public TextBoxTheClub()
    {

    }

    //Definindo o Destructor
    ~TextBoxTheClub()
    {

    }

Vou reescrever os métodos “OnLostFocus()”, “OnGotFocus()” e a propriedade “ForeColor” sendo respectivamente responsáveis por perder o foco, receber o foco e mudar cor da fonte, que neste caso defini como “DarkBlue”.

//Sobrescrever a propriedade cor da Fonte
public override Color ForeColor
{
     get
     {
         return Color.DarkBlue;
     }
     set
     {
         base.ForeColor = value;
     }
}

//Sobrescrever o evento ao receber o foco
protected override void OnGotFocus(EventArgs e)
{
     base.OnGotFocus(e);
     this.BackColor = System.Drawing.Color.LightYellow;
}

//Sobrescrever o evento ao perder o foco
protected override void OnLostFocus(EventArgs e)
{
     base.OnLostFocus(e);
     this.BackColor = Color.White;
}

public class Tipo : StringConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
     {
            return true;
     }
          
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
       {
return new StandardValuesCollection(new string[] { "CPF", "CNPJ", "PIS" });
       }
}

Foi necessário criar uma pequena classe denominada Tipo, herdando da “StringConverter”. Usaremos o “Override” do método “GetStandardValuesSupported” responsável por indicar se o conversor oferece ou não suporte a um conjunto de valores, retornando um booleano e o método “GetStandardvalues()“ que possibilita a manipulação de uma coleção de dados, que no caso específico identificamos como: CPF, CNPJ e PIS.

[TypeConverter(typeof(Tipo)), Category("validação")]

public string TipoValidacao
{
      get;
      set;
             
Para identificarmos o tipo de validação foi necessário criar uma propriedade “TipoValidacao” usando os operadores “Get” e “Set”, pois através deles que podemos recuperar e atribuir os valores descritos acima. Graças a esta propriedade que conseguimos manipular as configurações propostas pelo desenvolvedor.
 
protected override void OnValidating(System.ComponentModel.CancelEventArgs e)
{
     base.OnValidating(e);

     if (this.Text.Length > 0)
     {
           if (TipoValidacao == "CPF")
           {
                  if (ValidarCpf(this.Text) == true)
                  {
                        MessageBox.Show("CPF Válido!!");
                  }
                  else
                  {
                        MessageBox.Show("CPF Inválido!!");
                        this.Focus();
                  }
           }
           else if (TipoValidacao == "CNPJ")
           {
                 if (ValidarCnpj(this.Text) == true)
                 {
                       MessageBox.Show("CNPJ Válido!!");
                 }
                 else
                 {
                       MessageBox.Show("CNPJ Inválido!!");
                       this.Focus();
                 }
           }
           else if (TipoValidacao == "PIS")
           {
                if (ValidarPis(this.Text) == true)
                {
                      MessageBox.Show("PIS Válido!!");
                }
                else
                {
                      MessageBox.Show("PIS Inválido!!");
                      this.Focus();
                }
           }
     }
}

O evento “Onvalidating()” é executado no momento que saímos do Textbox, ou seja, o validamos. Este evento será responsável por chamar as funções de validações de CPF, CNPJ e PIS. No primeiro momento verificamos se o campo está preenchido com a propriedade “length” e logo em seguida usamos a propriedade pública “TipoValidacao” identificando o que o desenvolvedor deseja validar. Por final chamamos a função desejada. Não entrarei em detalhes como foram montadas as funções pelo fato deste artigo abordar a criação de componentes. Segue em seguida as funções “ValidarCpf()”, “ValidarCnpj()” e “ValidarPis()”.

public static bool ValidarCnpj(string cnpj)
{
    int[] multiplicador1 = new int[12] { 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
    int[] multiplicador2 = new int[13] { 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
    int soma;
    int resto;
    string digito;
    string tempCnpj;
    cnpj = cnpj.Trim();
    cnpj = cnpj.Replace(".", "").Replace("-", "").Replace("/", "");
       if (cnpj.Length != 14)
             return false;
    tempCnpj = cnpj.Substring(0, 12);
       soma = 0;
    for (int i = 0; i < 12; i++)
        soma += int.Parse(tempCnpj[i].ToString()) * multiplicador1[i];
    resto = (soma % 11);
    if (resto < 2)
        resto = 0;
    else
        resto = 11 - resto;
    digito = resto.ToString();
    tempCnpj = tempCnpj + digito;
    soma = 0;
    for (int i = 0; i < 13; i++)
        soma += int.Parse(tempCnpj[i].ToString()) * multiplicador2[i];
    resto = (soma % 11);
    if (resto < 2)
        resto = 0;
    else
        resto = 11 - resto;
    digito = digito + resto.ToString();
    return cnpj.EndsWith(digito);
}

public static bool ValidarCpf(string cpf)
{
    int[] multiplicador1 = new int[9] { 10, 9, 8, 7, 6, 5, 4, 3, 2 };
    int[] multiplicador2 = new int[10] { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };
    string tempCpf;
    string digito;
    int soma;
    int resto;
    cpf = cpf.Trim();
    cpf = cpf.Replace(".", "").Replace("-", "");
    if (cpf.Length != 11)
         return false;
    tempCpf = cpf.Substring(0, 9);
    soma = 0;

    for (int i = 0; i < 9; i++)
        soma += int.Parse(tempCpf[i].ToString()) * multiplicador1[i];
    resto = soma % 11;
    if (resto < 2)
        resto = 0;
    else
        resto = 11 - resto;
    digito = resto.ToString();
    tempCpf = tempCpf + digito;
    soma = 0;
    for (int i = 0; i < 10; i++)
        soma += int.Parse(tempCpf[i].ToString()) * multiplicador2[i];
    resto = soma % 11;
    if (resto < 2)
        resto = 0;
    else
        resto = 11 - resto;
    digito = digito + resto.ToString();
    return cpf.EndsWith(digito);
}

public static bool ValidarPis(string pis)
{
    int[] multiplicador = new int[10] { 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
    int soma;
    int resto;
    if (pis.Trim().Length != 11)
        return false;
    pis = pis.Trim();
    pis = pis.Replace("-", "").Replace(".", "").PadLeft(11, '0');

    soma = 0;
    for (int i = 0; i < 10; i++)
        soma += int.Parse(pis[i].ToString()) * multiplicador[i];
    resto = soma % 11;
    if (resto < 2)
        resto = 0;
    else
        resto = 11 - resto;
    return pis.EndsWith(resto.ToString());
}

Prontinho, acabamos de criar um pequeno componente utilizando o C#, Salve o projeto e o compile. Ver Imagem 02.

Figura 02: Compilando.

A Instalação

Clique com o botão direito na “Toolbox” e escolha “Choose Items...” para adicionar a .dll criada anteriormente. Figura 03.


Figura 03: Instalando o Componente.

No botão “Browse...” localize no diretório onde foi salvo, por exemplo:
C:\Diretorio\TextBoxTheClub\bin\Debug\TextBoxTheClub.dll

Figura 04: Adicionando no ToolBox.

A Imagem 05 mostra o “TextBoxTheClub” instalado corretamente na palheta de componentes.

Figura 05: “TextBoxTheClub” localizado na “ToolBox”.

Criando um exemplo prático

Para testá-lo basta encará-lo como um TextBox comum, mas com algumas funcionalidades a mais. Para isto crie um novo Projeto e adicione alguns “TextBoxTheClub” no formulário. Ver Imagem 06.

Figura 06: Criando um exemplo.

Clicando nas propriedades podemos conferir o tipo de validação que foi programado. Aproveite e escolha uma de cada tipo. Ver Imagem 07.

Figura 07: Tipo de Validação (CPF, CNPJ e PIS).

Rodando a aplicação podemos conferir a execução das funções no evento “Onvalidating()”, a troca de cor de acordo com o foco e o tipo pré-definido da cor da fonte. Ver Imagem 08 o exemplo em Run-Time.

Figura 08: Exemplo em Run-Time.

Conclusão

A criação de componentes se torna uma prática muito recomendada na programação Orientada a Objetos, sendo muito utilizada desde o início dos tempos. O principal intuito deste artigo foi de demonstrar que através de pequenos conceitos conseguimos economizar tempo e código no decorrer do desenvolvimento de aplicações. Abordei assuntos como: Herança de Classes, Sobrescrita de métodos e propriedades, criação de classes auxiliares e funções estáticas. Existem diversas formas e mecanismos para se desenvolver um componente, procurei neste artigo simplificar o máximo possível afim de um aprendizado maior. Fica assim, um grande abraço e até o mês que vem!

Nenhum comentário:

Postar um comentário