Search Forum
(57415 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Masked Edit Control written in C# that uses Regular Expressions
By Michael J. Bullard

We programmed a masked textbox control with C# that will convert the mask into a regular expression for each character in the field. It is designed to accept a user defined mask or a regular expression that defines each character in the field. If you pass it the mask as a string using the characters listed below, it will build the regular expression for you. It then loads the regular expression into an array which is used to validate and control the behavior of the field. There is an error provider message and a tooltip associated with the control.

The m_mask property is used to set the mask variable. Masks are set up for each character. Examples of valid mask strings and the regular expression they generate are detailed below:

           # = [0-9]
           9 = [\s0-9]
           A = [A-Z]
           a = [a-z]
           B = [A-Za-z]
           C = [A-Za-z0-9]
           M
           D
           Y
           / * , . - : ( ) { } = +
Examples:

If you set YourTextBox.m_mask = "9,999,999,999.99" then the field is set to accept only numeric characters and the 2 digit numbers will be less than 10 Trillion in length. Negative signs are displayed to the left of the number. Commas will be inserted into the number when you leave the field. Entering the field removes the commas and selects the entire number. Inserting and backspacing work to help you edit existing numbers.

If you set YourTextBox.m_mask = "9,999,999,99#.##" then the behavior of the field will be the same as above except that 0.00 is diplayed when you enter the field and the digits will be filled with zeros, if blank, when you leave the field. The "9" characters will be a space if not filled in.

If you set YourTextBox.m_mask = "(###)###-####" then the literals appear in the textbox when you enter a blank field. The textbox will accept numeric characters in the non literal positions. Inserting and backspacing work to help you edit existing numbers.

If you set YourTextBox.m_mask = "AaBC" then the first position will accept all upper case letters, the second position will accept all lower case letters, the third position will accept all upper and lower case letters and the fourth position will accept all letters and all numbers.

If you set YourTextBox.m_mask = "[A-JL-Z][012]-[6-9]/[jklm]" the first position will accept all upper case letters except K, the second position will accept only 0, 1 or 2, the third position will be equal to a literal dash, the fourth position will accept numbers of 6 through 9, the fifth position will be a literal forward slash and the last position will accept only lower case j, k, l or m.

The M, D and Y are designed to provide masks of "MM/DD/YYYY" or "MM/DD/YY". You could also rearrange the date to show the year first. The first M position will accept only 0 or 1. The first D position will accept only 0, 1, 2 or 3. The first Y position will accept only 0, 1 or 2 if there are four Y characters. The second Y position will accept 0 through 5 and 9 if there are only two Y characters. The second Y position will accept only 9 or 0 if there are four Y characters.

Additionally, an Error-Provider displays when the character entered does not match the regular expression. The mouse-hover event can be used on the form to display the string YourTextBox.stip as a tool-tip.

private void MaskText_Enter(object sender, System.EventArgs e)
{
  isleaving = false;
  EditRegx sd = (EditRegx) sender;
  string s = this.Text;
  int iSLength = s.Length;

  //**public class ETMFein : ETMString
  this.m_mask = "[A0-9][A0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9]";
  alphas = literals = true;
  sTip = "Enter a Federal ID number in ##-####### format";
  //**public class ETMMedSupID : ETMString
  this.m_mask = "[10][20][30][40][50][60][70]";
  alphas = true;
  sTip = "Enter a Med Sup ID";

  //**public class ETMZipCode : ETMString
  this.m_mask = "[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][\s-][\s0-9][\s0-9][\s0-9][\s0-9]";
  alphas = literals = true;
  sTip = "Enter a Zip Code in #####-#### format";
  //**public class ETMPhoneNumber : ETMString
  this.m_mask = "[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[\s0-9][\s0-9][\s0-9][\s0-9][\s0-9][\s0-9][\s0-9]";
  alphas = literals = true;
  sTip = "Enter a Phone Number in ###-###-####-####### format";
  //**public class ETMDecimal : ETMNumber
  this.m_mask = "999,999,999,999";
  isdigit = true;
  sTip = "Enter a Number with No Decimals";
      
  //**public class ETMPercent : ETMDecimal
  this.m_mask = "999,999,999,999.###%";
  isdigit = true;
  sTip = "Enter a Percent with Three Decimals";
      
  //**public class ETMDollar : ETMDecimal
  this.m_mask = "9,999,999,999,99#.##";
  isdecimal = true;
  sTip = "Enter a Dollar Value with Two Decimals";
            
  //**public class ETMNumber_1Dec : ETMDecimal
  this.m_mask = "99,999,999,999,99#.#";
  isdecimal = true;
  sTip = "Enter a Number with One Decimal";
            
  //**public class ETMNumber_2Dec : ETMDecimal
  this.m_mask = "9,999,999,999,99#.##";
  isdecimal = true;
  sTip = "Enter a Number with Two Decimals";
            
*/
//*********************************************************************      
  int iMaskLength = sd.mask.Length;
  if((isdecimal)||((isdigit)&&!(alphas)&&!(literals)))
  {
    string sdecdig = Trimit(s);
    if(negpressed)
      sdecdig = "-" + sdecdig;
    this.Text = sdecdig;
  }
  this.SelectAll();
  string strmask = this.mask;
  int numLiteral = setMaskArray(strmask);
  if((isdecimal)||((isdigit)&&!(alphas)&&!(literals)))
  {
    this.etmlength = this.regexArray.Count - numLiteral;
  }
  else
  {
    this.etmlength = this.regexArray.Count;
  }
  this.MaxLength = etmlength;

    //set the cursor in the blank mask and set alphas and isdigit flags
    //new alphas should position cursor after first literal.
    //digits and decimals should position cursor before dot
    //if digits and not alphas then right align
  int inumdec = 0;
  int cursorpos = 0;
  int firstalpha = 0;
  int literalpos = 0;
  if((iSLength <1)&&(iMaskLength >=1)) //entering a blank cell, display mask
  {
    for(int i = 0; i=1)) //entering a blank cell, display mask
    {
      string sMaskText = setBlankMaskText();
      this.Text = sMaskText;
    if((isdecimal)&&(!alphas)&&(!literals))
    {
      cursorpos = this.Text.IndexOf(".");
    }
      sd.setCursor = cursorpos;
      this.Select(sd.setCursor, 0);
    }
    if((iSLength >=1)&&(iMaskLength >=1)&&(alphas||literals)) //entering a non blank cell, display mask
    {
      string sMaskText = setMaskText(s);
      this.Text = sMaskText;
      this.SelectAll();
    }
      
}// end of MaskText_Enter
  

// *****************************************************************
    private void MaskText_MouseHover(object sender, System.EventArgs e)
    {

      EditRegx sd = (EditRegx) sender;
      ToolTip toolTip1 = new ToolTip();
      toolTip1.AutoPopDelay = 3000;
      toolTip1.InitialDelay = 1000;
      toolTip1.ReshowDelay  = 2000;
      toolTip1.ShowAlways = true;

      toolTip1.SetToolTip(sd, this.sTip);

    }


// ************************************************************
    private string setBlankMaskText()
    {
      string sBlankMask = "";
      string sWork1 = "";
      string sWork2 = "";
      int iArrayLen = this.regexArray.Count;
      int i = 0;
      int iFirstTime = 999;
      if((alphas)||(literals))
      {
        for(i = 0; i < iArrayLen; i++)
        {
          sWork1 = (string)regexArray[i];
          if((sWork1.StartsWith("L"))&&(sWork1.Substring(1,1)!= ","))
          {  
            sWork2 = sWork2 + sWork1.Substring(1, sWork1.Length - 1);  
          }
          else
          {  
            sWork2 = sWork2 + " ";  
            if(iFirstTime == 999)
            {
              iFirstTime = i;
            }
          }
          sBlankMask = sWork2;
          if(iFirstTime != 999)
          {
            this.setCursor = iFirstTime;  
          }
          else
          {
            this.setCursor = 0;      
          }
        }//end of for loop
      }//end of alphas
      if((isdigit)&&!(isdecimal)&&!(alphas)&&!(literals))
      {
        sBlankMask = "";
        setCursor = 0;      
      }
      if((isdigit)&&(isdecimal)&&!(alphas)&&!(literals))
      {
        sBlankMask = ".";// + sdecimal;
        setCursor = 0;      
      }

      return sBlankMask;
    }
//*****************************************
    private string setMaskText(string x)
    {
      string sMask = "";
      string sWork1 = "";
      string sWork2 = "";
      string s = x;
      string sTrimmed = Trimit(s);
      int iTrimLen = sTrimmed.Length;
      int iArrayLen = this.regexArray.Count;
      int ia = 0;
      int it = 0;
      if((alphas)||(literals))
      {
        for(ia = 0; ia < iArrayLen; ia++)
        {
          sWork1 = (string)regexArray[ia];
          if(sWork1.StartsWith("L"))
          {  
            sWork2 = sWork2 + sWork1.Substring(1, sWork1.Length - 1);  
          }
          else if(it < iTrimLen)
          {
            sWork2 = sWork2 + sTrimmed.Substring(it,1);  
            it = it + 1;
          }
          else
          {  
            sWork2 = sWork2 + " ";  
          }
        }//end of for loop
        sMask = sWork2;
      }//end of alphas
      if((isdigit)&&!(isdecimal)&&!(alphas)&&!(literals))
      {
        sMask = sTrimmed;
      }
      if((isdecimal)&&!(alphas)&&!(literals))
      {
        s = sTrimmed;
        int whereisdot = sTrimmed.IndexOf(".");
        if(whereisdot == -1)
        {
          sTrimmed = sTrimmed + ".";
          whereisdot = sTrimmed.IndexOf(".");
        }
        //if(!dotpressed)
        //{
        //  setCursor = whereisdot;
        //}
        //else
        //{
        //  setCursor = sTrimmed.Length;
        //}
        sMask = sTrimmed;
      }
      return sMask;
    }  //end of setMaskText

//*******************************************
    public int setMaskArray(string s)
    {
      int numL = 0;
      int numM = 0;
      int numD = 0;
      int numY = 0;
      int totY = 0;
      string strmask = s;
      int masklen = strmask.Length;

      ArrayList workArray1 = new ArrayList();
      string[] workArray2 = new string[masklen];
      string strWork  = "";
      string strWork1 = "";
      string strWork2 = "";
      int x = 0;
      for( int i = 0; i < masklen; i++)
      {
        strWork1 = "";
        strWork2 = "";
        strWork = strmask.Substring(i,1);
        if(strWork == "#")
        {  
          strWork1 = "[0-9]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "9")
        {  
          strWork1 = "[\s0-9]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "A")
        {  
          strWork1 = "[A-Z]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "a")
        {  
          strWork1 = "[a-z]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "B")
        {  
          strWork1 = "[A-Za-z]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "C")
        {  
          strWork1 = "[A-Za-z0-9]";
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }

        else if(strWork == "M")
        {  
          if(numM == 0)
          {
            strWork1 = "[0-1]";
            numM = 1;
          }
          else if(numM >= 1)
          {
            strWork1 = "[0-9]";
            numM = 2;
          }
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "D")
        {  
          if(numD == 0)
          {
            strWork1 = "[0-3]";
            numD = 1;
          }
          else if(numD >= 1)
          {
            strWork1 = "[0-9]";
            numD = 2;
          }
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if(strWork == "Y")
        {  
          if(numY == 0)//Y
          {
            totY = masklen - i;
            if(totY == 2)
            {
              strWork1 = "[0-59]";
            }
            else
            {
              strWork1 = "[0-2]";
            }
            numY = 1;
          }
          else if(numY == 1)//yY
          {
            if(totY == 2)
            {
              strWork1 = "[0-9]";
            }
            else
            {
              strWork1 = "[09]";
            }
            numY = 2;
          }
          else  //yyYorY
          {
            strWork1 = "[0-9]";
            numY = numY + 1;
          }
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
        }
        else if((strWork == "/")||(strWork == "*")||(strWork == ",")||(strWork == ".")
          ||(strWork == "-")||(strWork == ":")||(strWork == "(")||(strWork == ")")
          ||(strWork == "{")||(strWork == "}")||(strWork == "=")||(strWork == "+"))
        {  
          strWork1 = strWork;
          strWork1 = "L" + strWork1;
          workArray1.Add(strWork1);
          workArray2[x] = strWork1;
          x = x + 1;
          numL = numL + 1;
        }
        else if(strWork == "[")
        {  
          int remaining =  masklen - i;
          int test = 0;
          for(int r = 0; r < remaining; r++)
          {
            test = i + r;
            strWork1 = strmask.Substring(test,1);
            strWork2 = strWork2 + strWork1;
            if(strWork1 == "]")
            {
              i = test;
              break;
            }
          }
          if(strWork2.EndsWith("]"))
          {
            workArray1.Add(strWork2);
            workArray2[x] = strWork2;
            x = x + 1;
          }
          else
          {
            MessageBox.Show("error reading Mask, no closing bracket ]");
          }
          //i = test;  //already did this
        }//end of else if starts with "["
      }//end of big For Loop

      int j = workArray1.Count;
      int k = workArray2.Length;
      string[] workArray = new string[j];
      for(int y = 0; y < workArray1.Count; y++)
      {
        workArray[y] = (string)workArray1[y];
      }
      this.regexArray.Clear();
      this.regexArray.AddRange(workArray);
      int l = this.regexArray.Count;
      return numL;
    }//end of setMaskArray

//*******************************************
    private string GetKeyRegEx(int startcaret)
    {
      int iPos = startcaret;
      int iSizeRegExArray = this.regexArray.Count;//not set to instance of object, called from text changed
      string sReturnRegEx = "";
      if((iPos < iSizeRegExArray)&&(iPos != -1))
      {
        sReturnRegEx = (string)regexArray[iPos];
      }
      else
      {
        sReturnRegEx = "TooFar";//this.regexArray[iSizeRegExArray - 1];
      }
      return sReturnRegEx;
    }