Components

A TextBox for decimal values.

This is a C# component, so first of all create an UserControl class called DecimalTextBox. This most commonly done within a ComponentLibrary project. Pull a generic TextBox from the toolbox on to the component design form. We now have the DecimalTextBox.cs class, a Designer.cs and a resource DecimalTextBox.resx file. Now just substitute the code with that listed here.

The Decimal TextBox

    public partial class DecimalTextBox : UserControl
    {
        private Boolean allowSpace = false;
        //  Group seperator allows decimal nnn,nnn etc seperation of decimal numbers
        private Boolean allowGroupSeperator = false;
        //  Negative numbers require a different treatment to get to the two's complementary format
        //  so + and - are only allowed for Decimal numbers
        private Boolean allowNegativeSign = false;
        private Boolean allowPlus = false;
        //  Establish range limits
        private Decimal MaxDecValue = Decimal.MaxValue;
        private Decimal MinDecValue = Decimal.MinValue;

        public DecimalTextBox()
        {
            InitializeComponent();
            this.NumBox.Text = "0.0";
        }

        public Boolean AllowNegativeSign { get { return allowNegativeSign; } set { allowNegativeSign = value; } }
        public Boolean AllowPlus { get { return allowPlus; } set { allowPlus = value; } }
        public Boolean AllowGroupSeperator { get { return allowGroupSeperator; } set { allowGroupSeperator = value; } }

        public Decimal DecimalValue
        {
            //  Only decimal values
            get
            {
                try
                {
                    //  Filter off conversions like nn,.n and replace correct format on the text box
                    Decimal reply = Convert.ToDecimal(this.NumBox.Text);
                    if (allowGroupSeperator) this.NumBox.Text = reply.ToString(System.Globalization.CultureInfo.CurrentCulture.NumberFormat);
                    else this.NumBox.Text = Convert.ToString(reply);
                    return reply;
                }
                catch
                {
                    this.NumBox.Text = "Invalid";
                    return 0;
                }
            }
            set
            {
                NumberFormatInfo numberFormatInfo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
                if (value > MaxDecValue) value = MaxDecValue;
                else if (value < MinDecValue) value = MinDecValue;
                try
                {
                    if (allowGroupSeperator) this.NumBox.Text = Convert.ToString(value, numberFormatInfo);
                    else this.NumBox.Text = Convert.ToString(value);
                }
                catch { this.NumBox.Text = "Invalid"; }
            }
        }

        public new String Text { get { return this.NumBox.Text; } }

        public bool AllowSpace { set { this.allowSpace = value; } get { return this.allowSpace; } }

        public Color Text_Background
        {
            get
            {
                try { return NumBox.BackColor; }
                catch { return Color.AntiqueWhite; }
            }
            set { NumBox.BackColor = value; }
        }

        public Int32 MaxDigit { get { return NumBox.MaxLength; } set { NumBox.MaxLength = value; } }

        public Decimal MaximumDecimalValue
        {
            get { return MaxDecValue; }
            set
            {
                MaxDecValue = value;
                if (MaxDecValue < MinDecValue) MaxDecValue = Decimal.MaxValue;
                if ((MaxDecValue != Decimal.MaxValue) && (DecimalValue > MaxDecValue)) DecimalValue = MaxDecValue;
            }
        }

        public Decimal MinimumDecimalValue
        {
            get { return MinDecValue; }
            set
            {
                MinDecValue = value;
                if (MinDecValue > MaxDecValue) MinDecValue = Decimal.MinValue;
                if ((MinDecValue != Decimal.MinValue) && (DecimalValue < MinDecValue)) DecimalValue = MinDecValue;
            }
        }

        private void NumBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Restricts the entry of characters to digits (including hex), the negative sign,
            // the decimal point, and editing keystrokes (backspace).

            NumberFormatInfo numberFormatInfo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
            String decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
            String groupSeparator = numberFormatInfo.NumberGroupSeparator;
            String negativeSign = numberFormatInfo.NegativeSign;

            string keyInput = e.KeyChar.ToString();

            e.Handled = false;

            if (Char.IsDigit(e.KeyChar))
            {
                // Note the current value does not include the last key pressed
                //  This is a fractioned decimal
                String current_text = Text + e.KeyChar.ToString();
                try
                {
                    Decimal current_value = Convert.ToDecimal(current_text);
                    if ((current_value > MaxDecValue) || (current_value < MinDecValue))
                    {
                        e.Handled = true;
                        SystemSounds.Beep.Play();
                        return;
                    }
                }
                catch
                {
                    e.Handled = true;
                    SystemSounds.Beep.Play();
                    return;
                }
            }
            else if (keyInput.Equals(decimalSeparator))
            {
                String current_text = Text;
                //  if already > 2 length we are OK provided there is no '.' already
                if (current_text.Length > 2)
                {
                    if (!current_text.Contains(decimalSeparator)) return;
                }
                //  Cannot be 1st position or 2nd position if first is + or -
                else if ((current_text.Length == 2) && (current_text[0] != '+') && (current_text[0] != '-')) return;
                else if ((current_text.Length == 1) && (Char.IsDigit(current_text[0]))) return;
                e.Handled = true;
                SystemSounds.Beep.Play();
                return;
            }
            else if ((keyInput.Equals(groupSeparator)) && (allowGroupSeperator) && (Text.Length >= 1))
            {
                //  Cannot allow decimal seperator before group seperator
                String current_text = Text;
                if (!current_text.Contains(decimalSeparator)) return;
                e.Handled = true;
                SystemSounds.Beep.Play();
                return;
            }
            else if ((keyInput.Equals(negativeSign)) && (allowNegativeSign))
            {
                //  Only in first position
                if (Text.Length < 1) return;
                e.Handled = true;
                SystemSounds.Beep.Play();
                return;
            }
            else if (e.KeyChar == '\b') { return; }
            //    else if ((ModifierKeys & (Keys.Control | Keys.Alt)) != 0)
            //    {
            //     // Let the edit control handle control and alt key combinations
            //    }
            else if (this.allowSpace && e.KeyChar == ' ') { return; }
            else if ((allowPlus) && (e.KeyChar == '+'))
            {
                //  Only in first position or immediately after e
                if (Text.Length < 1) return;
                if (Text[(Text.Length - 1)] == 'e') return;
                e.Handled = true;
                SystemSounds.Beep.Play();
                return;
            }
            else
            {
                // Consume this invalid key and beep
                e.Handled = true;
                SystemSounds.Beep.Play();
            }
        }
    }

The text box has been sized for "normal" numbers by default, if a full definition is required, then a re-size will be needed. Optionally a group seperator for the thousands etc can be used. Note: if on evaluation the text is found to contain a contary format then the text will be modified when the value is read back.

The MaxDigit method refers to the maximum length of the text that can be entered in the box and the NumBox_KeyPress function handles all the text I/O.

        private void InitializeComponent()
        {
            this.NumBox = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // NumBox
            // 
            this.NumBox.AcceptsReturn = true;
            this.NumBox.BackColor = System.Drawing.SystemColors.Window;
            this.NumBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.NumBox.Location = new System.Drawing.Point(0, 0);
            this.NumBox.Margin = new System.Windows.Forms.Padding(0);
            this.NumBox.Name = "NumBox";
            this.NumBox.Size = new System.Drawing.Size(100, 20);
            this.NumBox.TabIndex = 0;
            this.NumBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.NumBox_KeyPress);
            // 
            // DecimalTextBox
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.NumBox);
            this.Name = "DecimalTextBox";
            this.Size = new System.Drawing.Size(100, 25);
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private System.Windows.Forms.TextBox NumBox;
    }

The designer can be copied or the equivalent generated by hand by changing the properties of the designer form. The properties must coincide with that required by the .cs code.