Desenvolvimento - C#

C#: Máscaras Dinâmicas para textBox com qualquer tipo numérico (CEP , CPF, CNPJ, MOEDA , DATA)

Este artigo foi criado para descrever passo-a-passo uma maneira dinâmica e eficaz de aplicar máscaras a conteúdos numéricos de qualquer tipo em um texBox, utilizando C#.

por Jorge Armando Andrade e Corrêa



Visando facilitar a vida de quem trabalha com desenvolvimento criei este artigo descrevendo passo-a-passo e elucidando através de código fonte uma maneira dinâmica e eficaz de aplicar máscaras a conteúdos numéricos de qualquer tipo em um texBox, utilizando C# (C Sharp).

Máscara, neste caso em questão, é um recurso de interface utilizado para assemelhar determinada informação(neste exemplo, numérica), visível no sistema, a maneira como estamos acostumados a manipulá-la na vida real.

Por exemplo, ao ver o número "00000000" inicialmente não podemos atribuir nenhuma informação característica adicional a ele, fora o fato de se constituir de uma cadeia numérica. Aplicando uma máscara, através da interface visual do sistema teremos "00000-000",o que pode nos levar a deduzir que este número se trata de um CEP. Este recurso é muito importante na prevenção de erros por parte do usuário assegurando ao mesmo a não necessidade de digitação de determinados dígitos que possam gerar equívocos durante a inserção dos dados no sistema.

Visando dinamizar este processo de "mascarar" um dado numérico em tempo real criei uma função principal que é capaz de adicionar uma mascara de qualquer tipo (CEP, CPF, CNPJ), o que pode facilitar a vida de alguns desenvolvedores, que como eu, inicialmente encontraram poucas referências a respeito.

Mas por que não usar um MaskedTextBox? Eu considero o MakedTextBox um tipo de textBox meio "engessado", com algumas limitações, e para o meu caso em questão achei mais eficiente a criação deste código fonte para manipulação do textBox.

Seguem abaixo algumas características do resultado expresso pelo código que será descrito:

- a inserção dos números ocorre da direita para a esquerda. Sendo assim num campo do tipo moeda (0,00) a inserção de seguidos "2" transcorreria da seguinte maneira:

0,02 -> 0,22 -> 2,22 -> 22,22

- a tecla BackSpace também se sucede da direita para a esquerda (sem perda visual da mascara) da seguinte maneira:

2,22 -> 0,22 -> 0,02

Acompanhem agora o detalhamento do código em questão:

Como exemplo, aplicarei máscara a dois tipos de dados: O CEF ("12345-678"), e o CNPJ("12345678/1234-12"). Note que no caso do CNPJ apresentam-se dois caracteres especiais. Farei isso para mostrar que o código abaixo pode aplicar a mascara com quantos caracteres forem necessários, bastando para isso definir a quantidade na chamada da função.

Passo 1: Primeiramente definiremos algumas propriedades iniciais para o textBox:

textAlign = rigth  (alinhamento do texto para direita)

text = 00000-000 (para CEP) ou text = 00000000/0000-00 (para CNPJ) – valores iniciais

Passo 2: Definiremos no evento Click do textBox o posicionamento do cursor para o final do mesmo, evitando assim que o usuário clique no meio da string para alterá-la:

private void txtCEP_Click(object sender, EventArgs e)

        {

            txtCEP.SelectionStart = txtCEP.Text.Length + 1;

        }

Passo 3: Chamaremos a função responsável pela mascara no evento KeyPress do textBox:

//atribui valor da tecla digitada e da string do texbox para dentro do objeto mascara

//posteriormente compara se a string é a tecla é numero, anulando-a caso contrário (mascara.mascaraNumero())

//e finalmente aplica a mascara (mascara.mascaraCEP)

private void txtCEP_KeyPress(object sender, KeyPressEventArgs e)

        {

            classeMascaraJa mascara = atribuiMascara((char)e.KeyChar, txtCEP.Text);

            if (!(e.Handled = mascara.mascaraNumero(9)))//este numero(9) é a quantidade de caracteres maximo do campo

                txtCEP.Text = mascara.mascaraCEP();

            txtCEP.SelectionStart = txtCEP.Text.Length + 1;

        }

private void txtCNPJ_KeyPress(object sender, KeyPressEventArgs e)

        {

            classeMascaraJa mascara = atribuiMascara((char)e.KeyChar, txtCNPJ.Text);

            if (!(e.Handled = mascara.mascaraNumero(16)))

                txtCNPJ.Text = mascara.mascaraCNPJ();

            txtCNPJ.SelectionStart = txtCNPJ.Text.Length + 1;

        }

private classeMascara atribuiMascara(char caractere, string texto)

        {   //preenche atributos mascara

            classeMascaraJa objetoMascara = new classeMascaraJa();

            objetoMascara.recebeTecla(caractere);

            objetoMascara.recebePalavra(texto);

            return objetoMascara;

        }

No evento KeyPress inicialmente chama-se uma função atribuiMascara, que é responsável por chamar a classe mascara instanciada.

Passo4:  Este passo é a codificação da classe mascara. O código fonte e alguns comentários seguem.

class classeMascaraJa

{

//ATRIBUTOS--------

private char tecla;

private string palavra;

private Int32 fator = 1;

//METODOS PRIVATE--

private void retiraCaractere(char carac)

{   //retirando caractere da string

       string[] campos = palavra.Split(carac);

       palavra = Convert.ToDouble(string.Concat(campos)).ToString();

}

private void acrescentaZeros(int normal, int backspace)

{   //acrescentado zeros a string

       while ((palavra.Length < normal) || ((palavra.Length < backspace) && (tecla == (char)Keys.Back)))

       {

             palavra = "0" + palavra;

       }

}

private void retornaFator()

{   //compara se backspace

       if (tecla == (char)Keys.Back)

             fator = 3;

}

public void limpaNumero(char simbolo, int min, int max)

{   //chama funcao para retirada de caracter e insercao de zeros

       retiraCaractere(simbolo);

       acrescentaZeros(min, max);

       retornaFator();

}

//funcao recebe quantidade de parter do numero, inicio e quantidade de caracteres de cada parte dentro da string, caracter e efetua qualquer tipo de mascara.

private void mascaraQualquer(Int32 quantidade, string[,] limites)

{

       string partes = "";

       Int32 contador = 0;

       while (contador < quantidade)

{

             partes += palavra.Substring(Convert.ToInt32(limites[contador, 0]), Convert.ToInt32(limites[contador, 1])) + limites[contador, 2];

             contador = contador + 1;

       }

       palavra = partes;

}

//METODODS PUBLICOS----

public void recebeTecla(char x)

{

       tecla = x;

}

public void recebePalavra(string y)

{

       palavra = y;

}

//metodo recebe caracter e retorna falso se numero

public bool mascaraNumero(Int32 maximo)

{

       if ((!char.IsNumber(tecla) || (palavra.Length >= maximo && Convert.ToInt32(palavra.Substring(0, 1)) != 0)) && (tecla != (char)Keys.Back))

             return true;

       else

             return false;

}

//aplica a mascara no formato 00000-000

public string mascaraCEP()

{

      limpaNumero("-", 7, 9);

      string[,] partes = { { "0", "5", "-" }, { "5", Convert.ToString(1 + fator), "" } };

      mascaraQualquer(2, partes);

      return palavra;

}

//aplica a mascara no formato 00000000/0000-00

public string mascaraCNPJ()

{

      string[] camposAux;

      palavra = string.Concat(camposAux = palavra.Split("/"));

      limpaNumero("-", 13, 15);

      string[,] partes = { { "0", "8", "/" }, { "8", "4", "-" }, { "12", Convert.ToString(1 * fator), "" } };

      mascaraQualquer(3, partes);

      return palavra;

}}

Passo 5: Não há passo 5! Este é todo codigo que será preciso para converter tanto CEP quanto CNPJ para suas devidas máscaras. Se analisarem verão que o codigo é simples e totalmente reutilizável.

A operação principal para conversao de um tipo numero se encontra dentro de dois métodos: um public e um private.

No caso do CNPJ por exemplo:

public string mascaraCNPJ()

{

      string[] camposAux;

      palavra = string.Concat(camposAux = palavra.Split("/"));

      limpaNumero("-", 13, 15);

      string[,] partes = { { "0", "8", "/" }, { "8", "4", "-" }, { "12", Convert.ToString(1 * fator), "" } };

      mascaraQualquer(3, partes);

      return palavra;

}}

Extraimos previamente o caractere “/”. Em seguinda efetuamos a limpeza do numero com relação ao caractere “–“ (Obs: no caso do CEP não é preciso uma estracao previa pois só há um tipo de caractere (“-“). Em datas, por exemplo, tambem somente seria necessário extrair o “/” usando o metodo limpaNumero()).

Os Números que seguem o caractere são “13” que corresponde ao valor mínimo de caracteres(somente numeros) menos 1, e “15” ao valor máximo de caracteres + 1. No caso de data, CEP, CNPJ, o numero máximo e mínimo são o mesmo, mas no caso de um tipo moeda o valor minimo é 3 e o maximo depende do limite de valor.

Feita a limpeza afetuaremos agora a aplicação da mascara: Primeiro é necessário entender que o numero será dividido em partes. No caso do CEP duas partes (parte1: 00000 e parte2: 000, ou seja, antes e depois do digito) e no CNPJ tres partes.

Na array(vetor bidimensional) “partes” serão inseriadas a posição do primeiro digito e a quantidade de digitos de cada parte da string(correspondendo a cada linha da matriz) seguido do caractere a ser inserido.

Ex.: CNPJ: 01234567/9999-00

Após extração dos digitos ficaria: 01234567999900

Diviriremos entao em partes:

Parte1: 01234567 ; minimo = posição 0 ; quantidade = 8; caracter = /

{“0”,”8”,”/”}

Parte2: 9999; minimo = posicao 8; quantidade = 4; caracter = “-“

{“8”,”4”,”-“}

Parte3: 00; minimo = 12;

quantidade = ?

aqui depende, se a pessoa tiver digitado um numero seria 1 para inserção de mais 1, ficando assim com dois, mas se o usuario tiver teclado o backspace teria de ser 3 para se diminuir 1 e ficar com a quantidade correta. Solucionando esta questão faço uso da variável “fator” multiplicada ao valor 1.

Quantidade =  1 * fator ; caracter = “”

{"12",Convert.ToString(1*fator),""}

Definidos os limites da string final, basta chamar o metodo “mascaraQualquer(3, partes);”, com a quantidade de partes(3) e a string particionada.

Acredito e prego o compartilhamento do conhecimento, por isso, espero ter ajudado alguem em outra parte do Brasil.

Jorge Armando Andrade e Corrêa

Jorge Armando Andrade e Corrêa - Bacharel em Sistemas de Informação pelo Centro Universitário do planalto de Araxá em dezembro de 2007. Experiência como analista de suporte e no desenvolvimento C#.net.