Interpret enter as tab WPF
Asked Answered
P

7

22

I want to interpret Enter key as Tab key in whole my WPF application, that is, everywhere in my application when user press Enter I want to focus the next focusable control,except when button is focused. Is there any way to do that in application life circle? Can anyone give me an example?
Thanks a lot!

Phago answered 16/5, 2009 at 3:27 Comment(1)
BabySmash by Scott Hanselman uses some Keyboard overridesTicking
P
40

You can use my EnterKeyTraversal attached property code if you like. Add it to the top-level container on a WPF window and everything inside will treat enter as tab:

<StackPanel my:EnterKeyTraversal.IsEnabled="True">
    ...
</StackPanel>
Praenomen answered 16/5, 2009 at 4:6 Comment(1)
the problem i am facing is that when the focus comes on a button, i want to execute the command and move on the next tab index. Is it possible to do so??Rabelais
I
11

Based on Richard Aguirre's answer, which is better than the selected answer for ease of use, imho, you can make this more generic by simply changing the Grid to a UIElement.

To change it in whole project you need to do this

  • In App.xaml.cs:

     protected override void OnStartup(StartupEventArgs e)
     {           
         EventManager.RegisterClassHandler(typeof(UIElement), UIElement.PreviewKeyDownEvent, new KeyEventHandler(Grid_PreviewKeyDown));
         base.OnStartup(e);
     }
    
     private void Grid_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
     {
         var uie = e.OriginalSource as UIElement;
    
         if (e.Key == Key.Enter)
         {
             e.Handled = true;
             uie.MoveFocus(
             new TraversalRequest(
             FocusNavigationDirection.Next));
         }
     }
    
  • Compile. And done it. Now you can use enter like tab. Note: This work for elements in the grid

Ingredient answered 31/7, 2016 at 21:1 Comment(0)
T
4

I got around woodyiii's issue by adding a FrameworkElement.Tag (whose value is IgnoreEnterKeyTraversal) to certain elements (buttons, comboboxes, or anything I want to ignore the enter key traversal) in my XAML. I then looked for this tag & value in the attached property. Like so:

    if (e.Key == Key.Enter)
    {
        if (ue.Tag != null && ue.Tag.ToString() == "IgnoreEnterKeyTraversal")
        {
            //ignore
        }
        else
        {
            e.Handled = true;
            ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }
Thithia answered 21/1, 2011 at 18:51 Comment(2)
Make sure to do this in the KeyDown event and not PreviewKeyDown or the caret will not move. Also, you don't specify what ue is but at least for me it needs to be e.Source.Malik
That's good. It works on TextBox if it has Tag="IgnoreEnterKeyTraversal" but I want same thing on ComboBox with IsEditable="true". In that scenario your trick does not work. Can you tell me how can I do that??Chivy
T
0

woodyiii, There is a function in the UIElement called PredictFocus() which by its name know its function, then you can check if that element is enabled or not so as to move the focus to it or not...

Thickleaf answered 4/9, 2010 at 12:45 Comment(0)
R
0

Here is Matt Hamilton's code, if anyone is wondering since his site is down apparently:

public class EnterKeyTraversal
{
    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    static void ue_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        var ue = e.OriginalSource as FrameworkElement;

        if (e.Key == Key.Enter)
        {
            e.Handled = true;
            ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }

    private static void ue_Unloaded(object sender, RoutedEventArgs e)
    {
        var ue = sender as FrameworkElement;
        if (ue == null) return;

        ue.Unloaded -= ue_Unloaded;
        ue.PreviewKeyDown -= ue_PreviewKeyDown;
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),

        typeof(EnterKeyTraversal), new UIPropertyMetadata(false, IsEnabledChanged));

    static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ue = d as FrameworkElement;
        if (ue == null) return;

        if ((bool)e.NewValue)
        {
            ue.Unloaded += ue_Unloaded;
            ue.PreviewKeyDown += ue_PreviewKeyDown;
        }
        else
        {
            ue.PreviewKeyDown -= ue_PreviewKeyDown;
        }
    }
}
Rigatoni answered 22/2, 2020 at 16:53 Comment(0)
P
0

Another, a more on/off implementation approach would be to use behaviors:

public class TextBoxEnterFocusesNextBehavior :
    Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewKeyDown += AssociatedObjectOnPreviewKeyDown;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewKeyDown -= AssociatedObjectOnPreviewKeyDown;
        base.OnDetaching();
    }

    private void AssociatedObjectOnPreviewKeyDown(object sender, KeyEventArgs args)
    {
        if (args.Key != Key.Enter) { return; }

        args.Handled = true;
        AssociatedObject.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }
}

Usage example:

<UserControl xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:behaviors="clr-namespace:Your.Namespace.To.Behaviors"
             ...>
    <DockPanel>
        <TextBox x:Name="TextBoxWithBehavior"
                 DockPanel.Dock="Top">
            <b:Interaction.Behaviors>
                <behaviors:TextBoxEnterFocusesNextBehavior />
            </b:Interaction.Behaviors>
        </TextBox>
        <TextBox x:Name="TextBoxWithoutBehavior"
                 DockPanel.Dock="Top" />
        <TextBox x:Name="AnotherTextBoxWithBehavior"
                 DockPanel.Dock="Top">
            <b:Interaction.Behaviors>
                <behaviors:TextBoxEnterFocusesNextBehavior />
            </b:Interaction.Behaviors>
        </TextBox>
    </DockPanel>
</UserControl>
Phagy answered 6/12, 2022 at 12:4 Comment(0)
R
0

My solution:

public class MoveToNext : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
        if (parameter is RoutedEventArgs routedEventArgs && routedEventArgs.OriginalSource is FrameworkElement element)
        {
            routedEventArgs.Handled = true;
            element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }
}

Usage:

<StackPanel>
    <i:Interaction.Triggers>
        <i:KeyTrigger Key="Return">
            <util:MoveToNext/>
        </i:KeyTrigger>
    </i:Interaction.Triggers>
<!-- put your controls here -->
</StackPanel>

If you want the behavior to be attached to only one control instead of all controls within a layouter, simply add the <i:Interaction.Triggers block to that specific control.

Refractory answered 1/2, 2023 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.