I'm building a custom DatePicker in WPF using a UserControl. My control inside it has 3 TextBoxes that take care of indicating day month and year based on the cultureInfo.
I am trying to move the focus from one textbox to another to simplify data entry but I always have the same problem, the focus moves but always ends up at the first of the 3 textboxes inside the control.
Here is the code of TextChanged event that is one for all three texboxes:
private void _DateTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
EvolutionTextbox textBox = sender as EvolutionTextbox;
string tagText = textBox.TagText.ToString();
int value;
bool emptyText = false;
bool isNumber = Int32.TryParse(textBox.InputText, out value);
if (textBox.InputText == "") {
emptyText = true;
}
_UnregisterEvents();
int year = 2024; // default value for year
int month = 1; // default value for month
int day = 1; // default value for day
// get current input from textboxes
if (_YearTextBox.InputText != "" && _YearTextBox.InputText.Count() == 4) {
year = Int32.Parse(_YearTextBox.InputText);
}
if (_MonthTextBox.InputText != "" && Int32.Parse(_MonthTextBox.InputText) < 12 && Int32.Parse(_MonthTextBox.InputText) > 0) {
month = Int32.Parse(_MonthTextBox.InputText);
}
if (_DayTextBox.InputText != "") {
day = Int32.Parse(_DayTextBox.InputText);
}
int maxDay = DateTime.DaysInMonth(year, month);
switch (tagText) {
case "d": // Day
if (value <= 0 || value > maxDay) {
((EvolutionTextbox)sender).InputText = maxDay.ToString();
}
break;
case "M": // Month
if (value <= 0 || value > 12) {
((EvolutionTextbox)sender).InputText = "12";
}
else if (value <= 12) {
maxDay = DateTime.DaysInMonth(year, value);
if (day > maxDay) {
_DayTextBox.InputText = maxDay.ToString();
}
}
break;
case "yyyy": // Year
if (value <= 0 || value > 9999) {
((EvolutionTextbox)sender).InputText = "9999";
}
else if (value > 0) {
maxDay = DateTime.DaysInMonth(value, month);
if (day > maxDay) {
_DayTextBox.InputText = maxDay.ToString();
}
}
break;
}
// If empty set empty string
if (emptyText) {
((EvolutionTextbox)sender).InputText = "";
}
_RegisterEvents();
//jump between textboxes
if ((tagText == "d" || tagText == "M") && textBox.InputText.Length == 2) {
TraversalRequest req = new TraversalRequest(FocusNavigationDirection.Next);
MoveFocus(req);
}
else if (tagText == "yyyy" && textBox.InputText.Length == 4) {
TraversalRequest req = new TraversalRequest(FocusNavigationDirection.Next);
MoveFocus(req);
}
}
I also tried putting KeyboardNavigation.TabNavigation="Contained" and also KeyboardNavigation.TabNavigation="Local" but they did not have the desired effect. I also tried setting the TabIndex of the various controls by putting TabIndex = 1,2,3 for the respective controls.
I do not understand what may be missing or what I am doing wrong!
The behavior you are observing is correct: you are always calling
FrameworkElement.MoveFocuson the parentUserControlto move the focus to the next element. And the next element in the hierarchy is the firstTextBox. Unless you move the elements inside the child element tree the next element relative to theMoveFocuscaller will never change.You have to call
MoveFocuson the currently focused element to continue focus traversal.Assuming that you use the same
_DateTextBox_TextChangedevent handler for allTextBox.TextChangedevents of the participatingTextBoxelements then you must change the focus navigation part as follows: