Restricting input on winform text boxes

How do you get a text box to only support positive floating point numbers on a Windows Form text box? (I know. I know. This is old school. However, it does pay the bills.)

One way that I thought was appealing was to implement the KeyDown event and control the key-presses; like this:

private void txtBowelMovementsPerDay_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
    // Allow numbers from keyboard
    if (e.KeyData >= Keys.D0 && e.KeyData <= Keys.D9)         return;     // Allow numbers from number pad     if (e.KeyData >= Keys.NumPad0 && e.KeyData <= Keys.NumPad9)
        return;

    // Allow periods from keyboard and number pad
    if (e.KeyData == Keys.Decimal || e.KeyData <= Keys.OemPeriod)
    {
        // but only one
        if (!txtBowelMovementsPerDay.Text.Contains('.'))
            return;
    }

    // Allow alt and shift to work
    if (e.Alt || e.Shift)
        return;

    // Allow the special keys to work
    switch (e.KeyData)
    {
        case Keys.End:
        case Keys.Enter:
        case Keys.Home:
        case Keys.Back:
        case Keys.Delete:
        case Keys.Escape:
        case Keys.Tab:
        case Keys.Left:
        case Keys.Right:
            return;
    }

    // Invalid input
    e.SuppressKeyPress = true;
    e.Handled = true;
}

A friend pointed out that while this was cool (ok, I may have change the tone there), it doesn’t internationalize well because a) it assumes the US keyboard layout and b) it assumes a ‘.’ is always the radix point. Bad, bad, bad.

Instead he turned me onto letting Windows do its job and checking the validity of the float to begin with and enabling the user to press “OK”. Like this…

private void txtBowelMovementsPerDay_TextChanged(object sender, EventArgs e)
{
    btnOk.Enabled = TrackSpacingMicronsTextBoxIsValid();
}

private bool TrackSpacingMicronsTextBoxIsValid()
{
    float trackSpacingMicrons;

    // is it a valid float?
    if (float.TryParse(txtBowelMovementsPerDay.Text, out trackSpacingMicrons))
    {
        // is it a positive number?
        if (trackSpacingMicrons <= 0)
            return false;
        return true;
    }
    else
        return false;
}

This is a much better approach and facilitates i18n. While Winforms is old-school, the problem is nicely solved in WPF.

<TextBox Name="txtBowelMovementsPerDay" TextWrapping="Wrap" Text="{Binding Path=BowelMovementsPerDay, Mode=TwoWay, 
    UpdateSourceTrigger=PropertyChanged,StringFormat={}{##.##}}"></TextBox>

For systems where you must make a decision to validate or preempt keystrokes, validation will always be best. By validation, I mean that you do not let the user continue unless all the data is correct. This is true with web page development as well as Javascript will parse floats based on locale.

Leave a Reply

Your email address will not be published. Required fields are marked *