I want to move to the next control when I press the Enter key instead of the Tab key in a WPF MVVM application. How can I achieve this?
I have used "tag" property of textbox for skip move focus. i.e. if some time you dont want to move to next control on enter key pressed (in the case of multiline text box where enter is required to create new line). Just set tag property to 1. Show activity on this post.
sample solution: using PreviewKeyDown in the stack panel. The Preview... is a bubble up so the event can be handled at a higher level. You may need to handle this differently for different element types, like button it seems should keep the enter key and not change focus on the enter key.
First that occured to add trigger to each element that will invoke when PreviewKeyDown fires. Also add Dependency property and bind FrameworkElement that you wont to bring focus at. Within trigger provide setting Focus to binded element.
If the user presses ENTER you can call Control.SelectNextControl () or SendKeys.Send (" {TAB}"). :) +5 good answer. :-) this way is proper to achieve your goal. If you think that it is proper why you give me a 2? You know that 1 and 2 are down-votes and 4 and 5 are up-votes, right? :) Thanks for your answer.
Below is an attached property that I've used for just this.
First, example usage:
<TextBox Width="100" Text="{Binding Name, Mode=TwoWay}" UI:FocusAdvancement.AdvancesByEnterKey="True" />
(UI is the namespace alias for where I've defined the following.)
The attached property:
public static class FocusAdvancement { public static bool GetAdvancesByEnterKey(DependencyObject obj) { return (bool)obj.GetValue(AdvancesByEnterKeyProperty); } public static void SetAdvancesByEnterKey(DependencyObject obj, bool value) { obj.SetValue(AdvancesByEnterKeyProperty, value); } public static readonly DependencyProperty AdvancesByEnterKeyProperty = DependencyProperty.RegisterAttached("AdvancesByEnterKey", typeof(bool), typeof(FocusAdvancement), new UIPropertyMetadata(OnAdvancesByEnterKeyPropertyChanged)); static void OnAdvancesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var element = d as UIElement; if(element == null) return; if ((bool)e.NewValue) element.KeyDown += Keydown; else element.KeyDown -= Keydown; } static void Keydown(object sender, KeyEventArgs e) { if(!e.Key.Equals(Key.Enter)) return; var element = sender as UIElement; if(element != null) element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); } }
You also said "instead of tab," so I'm wondering if you want to suppress the ability to use tab in the usual way. I'd advise against it, as it is a common, well known paradigm, but if that is the case, you can add a PreviewKeyDown
handler in the attached property, check for the tab key, and set Handled = true
for the event args.
If you only want it to work for a few text boxes, Jay's answer is best.
If you want your whole application to work that way, makwana.a's answer is better but can be improved.
Below is my modification of makwana.a's answer, which I have used in numerous applications. It also includes support for moving to the next control via enter if the active control is a check box. Instead of using the tag property to decide whether or not the focus should move, I used the AcceptsReturn
property of the text box. I did this because it defaults to false and will only be set to true on multi-line text boxes. In that case, you won't want the focus to move to the next control on enter anyway.
Declare these event handlers in the OnStartup void of App.xaml
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.KeyDownEvent, new KeyEventHandler(TextBox_KeyDown)); EventManager.RegisterClassHandler(typeof(CheckBox), CheckBox.KeyDownEvent, new KeyEventHandler(CheckBox_KeyDown));
Here are the rest of the methods needed to make it work application wide.
void TextBox_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter & (sender as TextBox).AcceptsReturn == false) MoveToNextUIElement(e); } void CheckBox_KeyDown(object sender, KeyEventArgs e) { MoveToNextUIElement(e); //Sucessfully moved on and marked key as handled. //Toggle check box since the key was handled and //the checkbox will never receive it. if (e.Handled == true) { CheckBox cb = (CheckBox)sender; cb.IsChecked = !cb.IsChecked; } } void MoveToNextUIElement(KeyEventArgs e) { // Creating a FocusNavigationDirection object and setting it to a // local field that contains the direction selected. FocusNavigationDirection focusDirection = FocusNavigationDirection.Next; // MoveFocus takes a TraveralReqest as its argument. TraversalRequest request = new TraversalRequest(focusDirection); // Gets the element with keyboard focus. UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; // Change keyboard focus. if (elementWithFocus != null) { if (elementWithFocus.MoveFocus(request)) e.Handled = true; } }
Edit
I updated the code to mark the keystroke as handled if the movement was successful and also toggle the checkbox since the key was handled and will no longer reach it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With