Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF TextBox.Focus() annoyance

Tags:

focus

wpf

textbox

I'm very new to .Net and WPF and have a problem. The code is a snippet. I have 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?

like image 660
Moss Avatar asked Jul 31 '09 10:07

Moss


1 Answers

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)
like image 178
Kent Boogaart Avatar answered Oct 26 '22 23:10

Kent Boogaart