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