Freigeben über


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

  • Anonymous
    May 23, 2006
    Thank you Irena - this is great!

  • Anonymous
    May 24, 2006
    The comment has been removed

  • Anonymous
    May 27, 2006
    PingBack from http://adamcaudill.com/2006/05/27/maskedtextbox-madness/

  • Anonymous
    June 21, 2006
    At a customer's site, an application needed to format and accept formatted input for currencies. They...

  • Anonymous
    June 21, 2006
    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

  • Anonymous
    January 18, 2007
    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

  • Anonymous
    January 19, 2007
    Use zeros instead of # in your mask; e.g. Mask = "0000.00" and you should get the expected result

  • Anonymous
    February 27, 2007
    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.

  • Anonymous
    January 16, 2008
    Do you have a VB.NET implementation?

  • Anonymous
    July 10, 2008
    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; }

  • Anonymous
    July 24, 2008
    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.

  • Anonymous
    August 04, 2008
    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.

  • Anonymous
    February 08, 2009
    PingBack from http://www.sascha-hennig.de/csharp/maskedtextbox-and-custom-types