SYSK 87: A Better MaskedTextBox For Currency Fields


You may want to save this one off and put it in your personal toolbox…


 


The MaskedTextBox that comes with .NET has a few limitations – it does not automatically shift your digits.  For example, if I enter a mask of 0000.00, and enter number 12, I’d expect to see __12.00; instead, I see 12__.__.


 


Below is a custom control that “fixes” that behavior.  NOTE: for the control to work right, use zeros in the mask, not nines or pound sign.


 


public class CurrencyTextBox : System.Windows.Forms.MaskedTextBox


{


    public CurrencyTextBox()


    {


        base.TextMaskFormat = System.Windows.Forms.MaskFormat.IncludePromptAndLiterals;


    }


 


    public bool TryGetValue(out decimal data)


    {


        return decimal.TryParse(RemovePromptAndLiterals(this.Text), out data);           


    }


 


    public decimal Value


    {


        get


        {


            decimal result = 0;


            TryGetValue(out result);


 


            return result;


        }


        set


        {


            base.Text = ReplaceLeadingZeros(value.ToString(this.Mask));


        }


    }


 


    private string RemovePromptAndLiterals(string data)


    {


        return data != null ? data.Replace(” “, “”).Replace(this.PromptChar.ToString(), “”).Replace(“$”, “”) : “”;


    }


 


    protected override void OnValidated(EventArgs e)


    {


        decimal data = 0;


        if (TryGetValue(out data) == true)


        {


            base.Text = ReplaceLeadingZeros(data.ToString(this.Mask));


        }


       


        base.OnValidated(e);


    }


 


    protected override void OnTextChanged(EventArgs e)


    {


        base.OnTextChanged(e);


    }


 


    public override string Text


    {


        get


        {


            return base.Text;


        }


        set


        {


            decimal data = 0;


            if (decimal.TryParse(RemovePromptAndLiterals(value), out data) == true)


            {


                base.Text = ReplaceLeadingZeros(data.ToString(this.Mask));


            }


            else


            {


                base.Text = value;


            }


        }


    }


 


    protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)


    {


        if (e.KeyChar == ‘.’)


        {


            decimal data = 0;


            if (TryGetValue(out data) == true)


            {


                string mask = this.Mask.Replace(“.00”, “.##”).Replace(“.99”, “.##”);


                base.Text = ReplaceLeadingZeros(data.ToString(mask));


            }


        }


 


        base.OnKeyPress(e);


    }


 


    protected string ReplaceLeadingZeros(string data)


    {


        char[] chars = data.ToCharArray();


 


        for (int i = 0; i < chars.Length; i++)


        {


            if (chars[i] != ‘$’ && chars[i] != ‘ ‘)


            {


                if (chars[i] == ‘0’)


                    chars[i] = this.PromptChar;


                else


                    break;


            }


        }


 


        return new string(chars);


    }


}



[6/21/2006]  Check out Sven Aelterman’s post where he improved on the code above by adding culture awareness and thousand separator awareness:  http://www.adduxis.com/blogs/blogs/sven/archive/2006/06/21/18.aspx 


 

Comments (13)

  1. Ray Muirhead says:

    Thank you Irena – this is great!

  2. Joel@YA says:

    Thanks for this.  As a suggestion, some comments in the code would be helpful.  If I wanted to expand this to include support of ‘##’ hash marks, what would that look like?

  3. Sven's Blog says:

    At a customer’s site, an application needed to format and accept formatted input for currencies. They…

  4. I’ve added comments to Irena’s code, and then set out to add support for non-US English cultures and the thousand separator.

    The result is available through http://www.adduxis.com/blogs/blogs/sven/archive/2006/06/21/18.aspx

  5. NickO says:

    Shifting of numbers to the left is the least of problems I’d worry about.

    Try to set the Mask = "####.##", then set

    maskedtextbox1.text = "15.25"

    The resul yo’d get is 1525.  ". The mask completely ignores the decimal point.

    You are right: you’d need to write a function that would take care of inefficiencies of Masked Textbox design

    NickO

  6. irenak says:

    Use zeros instead of # in your mask; e.g. Mask = "0000.00" and you should get the expected result

  7. hi irena, nice post but i have some comments. it is better if you will use the CultureInfo and CurrentCulture of the applications so you can use the correct decimal separators, parethesis, currency symbols and numbver digits. Replacing "$" sign is no good to me eso for multi-currency applications such as e-commerce, trading, sales automations and erp.

  8. mike says:

    Do you have a VB.NET implementation?

  9. Valmir says:

    I’ve found a simplier way:

    private void maskedTextBox1_KeyPress(object sender, KeyPressEventArgs e)

    {

    string buff = "";

    int i;

    if (maskedTextBox1.MaskCompleted)

    {

     e.Handled = true;

     return;

    }

    char[] chars = maskedTextBox1.Text.PadLeft(5, ‘ ‘).ToCharArray();

    for (i = 0; i < chars.Length-1; i++)

      chars[i] = chars[i+1];

    chars[i] = e.KeyChar;

    for (i = 0; i < chars.Length; i++)

      buff += chars[i];

    maskedTextBox1.Text = buff;

    }

  10. Vikash says:

    I am using a masked textbox to ip date in following format dd-MMM-yyyy. I’ve set the mask property as 00-AAA-0000 However if i assign text property of Masked textbox to a value like 11Jul2008 i can not delete first two characters from the masked textbox unless i delete remaining six characters first. Any idea what could be the reason.

  11. Netcigos says:

    Hi I made a Inherited control about it. But It don´t work like see in this post. I put the control on a win forms , and then put the mask 0000.00. When i imput the digit in the control , it don´t shift the digit to right.

    Any boy can tell me how use this control on a win form.