tags:

views:

1371

answers:

1

Hi. I'm very new to .Net and WPF and have a problem. The code is a snippet. I have those TextBoxes to enter dates. I check on correct input using GotFocus and LostFocus events.

<TextBox Name="sdDay" Width="40" Text="Day" GotFocus="DateDay_GotFocus" LostFocus="DateDay_LostFocus" Padding="5,5,5,5" HorizontalContentAlignment="Center" Focusable="True"/>
<TextBox Name="sdMonth" Width="50" Text="Month" GotFocus="DateMonth_GotFocus" LostFocus="DateMonth_LostFocus" Padding="5,5,5,5" Margin="5,0,0,0" HorizontalContentAlignment="Center" Focusable="True"/>
<TextBox Name="sdYear" Width="50" Text="Year" GotFocus="DateYear_GotFocus" LostFocus="DateYear_LostFocus" Padding="5,5,5,5" Margin="5,0,0,0" HorizontalContentAlignment="Center" Focusable="True"/>

And the code:

private void DateDay_GotFocus(object sender, RoutedEventArgs e)
    {
        if (((TextBox)sender).Text == "Day")
            ((TextBox)sender).Text = string.Empty;
    }

private void DateDay_LostFocus(object sender, RoutedEventArgs e)
    {
        if (((TextBox)sender).Text == string.Empty)
            ((TextBox)sender).Text = "Day";
        else
            CheckForCorrectDateDay((TextBox)sender);
    }

private void CheckForCorrectDateDay(TextBox b)
    {
        int day = 0;

        try
        {
            day = int.Parse(b.Text);

            if (day < 0 || day > 31)
            {
                MessageBox.Show("Please enter a correct day.");
                b.Text = string.Empty;
                b.Focus();
            }
        }
        catch (FormatException)
        {
            MessageBox.Show("Please enter a number.", "Incorrect Input", MessageBoxButton.OK, MessageBoxImage.Warning);
            b.Text = string.Empty;
            b.Focus();
        }
        catch (Exception)
        {
            throw;
        }
    }

Now what I want it to do is check for correct input, and if that fails, set the focus back to whatever TextBox had an incorrect entry.

It doesn't work though. After I enter a number outside the range (or letter), the MessageBox will show but the focus shifts to the next TextBox which is for entering the month.

What am I doing wrong?

+4  A: 

Your technique for validation here is, to be frank, very poor. That said, I believe the problem is just that WPF is handling the tab after you've set focus, so it is setting focus back to the next item in the focus order.

A simple workaround would be to dispatch a separate message that is processed after the current message:

if (day < 0 || day > 31)
{
    MessageBox.Show("Please enter a correct day.");
    b.Text = string.Empty;

    Dispatcher.BeginInvoke((ThreadStart)delegate
    {
        b.Focus();
    });
}

Doing this ensures that WPF completely processes the LostFocus event handler before it processes the separate message to set focus on the erroneous control.

In terms of how you could tackle this problem in a much nicer way, you could:

  1. Define a view model with properties for Day, Month, and Year (prerequisite: read up on the MVVM pattern)
  2. Implement IDataErrorInfo on the view model
  3. Bind the TextBoxes in the UI to the corresponding properties on the view model (prerequisite: read up on WPF data binding)

HTH, Kent

Kent Boogaart
Thank you for the answer. I understand your explanation of the problem but not exactly what the solution does. Like I said, I'm very new to .Net.And I wouldn't mind some tips on better validation techniques.
Moss
Sure thing. Added some more detail to my post.
Kent Boogaart
I'd like to echo Kent's comment - forcing the focus back is a sure way to make your users angry.
Anderson Imes
1 up for kent, don't try to treat all those events, better use some validation interface: implement IDataErrorInfo or use ValidationRules to validate input.
Simpzon