WPF TextBox.Focus() annoyance
focus, textbox, wpf
Solution
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:
- Define a view model with properties for Day, Month, and Year (prerequisite: read up on the MVVM pattern)
- Implement `IDataErrorInfo` on the view model
- Bind the `TextBox`es in the UI to the corresponding properties on the view model (prerequisite: read up on WPF data binding)
Problem
I'm very new to .Net and WPF and have a problem. The code is a snippet. I have `TextBox`es 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?