首页 文章

在WPF中转到Enter keypress上的下一个控件

提问于
浏览
30

当我在WPF MVVM应用程序中按Enter键而不是Tab键时,我想转到下一个控件 . 我怎样才能做到这一点?

7 回答

  • 41

    Jay的答案很好,如果你只想让它适用于几个文本框,但如果你希望你的整个应用程序以这种方式工作,我绝对赞成makwana.a的答案 . 这是我对makwana.a在C#中使用的答案的修改 . 如果活动控件是一个复选框,我还支持通过输入继续下一个控件 .

    另请注意,我不使用tag属性来表示焦点是否应继续,而是使用文本框的AcceptsReturn属性,因为它默认为false,您只需在所需的文本框中将其设置为true用作多行,即不应将焦点移到Enter键上 .

    在OnStartup void App.xaml中声明这些事件处理程序

    EventManager.RegisterClassHandler(typeof(TextBox), TextBox.KeyDownEvent, new KeyEventHandler(TextBox_KeyDown));
            EventManager.RegisterClassHandler(typeof(CheckBox), CheckBox.KeyDownEvent, new KeyEventHandler(CheckBox_KeyDown));
    

    以下是使其适用于应用程序所需的其他方法 .

    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

    我更新了代码,以便在移动成功时将按键标记为已处理,并且还会切换复选框,因为密钥已处理并且将不再到达 .

  • 3

    以下是我用过的附属物 .

    一,示例用法:

    <TextBox Width="100"
             Text="{Binding Name, Mode=TwoWay}"
             UI:FocusAdvancement.AdvancesByEnterKey="True" />
    

    (UI是我定义以下内容的命名空间别名 . )

    附属物:

    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));
        }
    }
    

    你还说"instead of tab,"所以我建议反对它,因为它是一个常见的,众所周知的范例,但如果是这种情况,你可以在附加属性中添加 PreviewKeyDown 处理程序,检查tab键,并设置 Handled = true 为事件args .

  • 0

    示例解决方案:在堆栈面板中使用PreviewKeyDown . 预览...是一个泡沫,因此可以在更高级别处理事件 . 对于不同的元素类型,您可能需要以不同的方式处理它,例如按钮似乎应该保持回车键而不是将注意力更改为回车键 .

    这是xaml:

    <StackPanel PreviewKeyDown="StackPanel_PreviewKeyDown" >
        <TextBox >
            Hello
        </TextBox>
        <TextBox>
            World
        </TextBox>
        <TextBox>
            test
        </TextBox>
    </StackPanel>
    

    以下是代码背后的代码:

    private void StackPanel_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            TextBox s = e.Source as TextBox;
            if (s != null)
            {
                s.MoveFocus(new TraversalRequest( FocusNavigationDirection.Next));
            }
    
            e.Handled = true;
        }
    }
    

    这只是一个用于概念验证的沙箱 .

    快乐编码......

  • 11

    将此代码写入应用程序文件的onstartup事件中

    EventManager.RegisterClassHandler(GetType(TextBox), TextBox.KeyDownEvent, New RoutedEventHandler(AddressOf TextBox_KeyDown))
    

    然后将TextBox_KeyDown sub定义为

    Private Sub TextBox_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Input.KeyEventArgs)
        If e.Key = Key.Enter And TryCast(sender, TextBox).Tag <> "1" Then
            ' Creating a FocusNavigationDirection object and setting it to a
            ' local field that contains the direction selected.
            Dim focusDirection As FocusNavigationDirection = FocusNavigationDirection.Next
    
            ' MoveFocus takes a TraveralReqest as its argument.
            Dim request As New TraversalRequest(focusDirection)
    
            ' Gets the element with keyboard focus.
            Dim elementWithFocus As UIElement = TryCast(Keyboard.FocusedElement, UIElement)
    
            ' Change keyboard focus.
            If elementWithFocus IsNot Nothing Then
                elementWithFocus.MoveFocus(request)
            End If
        End If
    End Sub
    

    我使用了文本框的“tag”属性来跳过移动焦点 . 即如果有一段时间你不想在按下输入键的情况下移动到下一个控件(在多行文本框的情况下需要输入以创建新行) . 只需将tag属性设置为1即可 .

  • 25

    希望这个帮助:使用AttachedProperty http://madprops.org/blog/enter-to-tab-as-an-attached-property/

    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;
            }
        }
    }
    

    <StackPanel my:EnterKeyTraversal.IsEnabled="True">
    
  • 1

    首先发生的事件是向 PreviewKeyDown 触发时将调用的每个元素添加触发器 . 还要添加Dependency属性并绑定 FrameworkElement ,您不会将焦点放在 . 在触发器内提供绑定元素的设置 Focus .

  • 3

    使用代码隐藏:

    我想出了下面的代码 . 请注意,它没有设置e.Handled . 此外,MoveFocus_Next不会返回移动焦点是否成功,而是返回参数是否为空 . 您可以根据需要添加或删除要处理的控件类型 . 代码是为应用程序的MainWindow编写的,但也处理其他窗口 . 您还可以从App_Startup事件调整代码以进行调用 .

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    public partial class MainWindow : Window
    {
        private bool MoveFocus_Next(UIElement uiElement)
        {
            if (uiElement != null)
            {
                uiElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                return true;
            }
            return false;
        }
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(Window_PreviewKeyUp));
        }
    
        private void Window_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                IInputElement inputElement = Keyboard.FocusedElement;
                if (inputElement != null)
                {
                    System.Windows.Controls.Primitives.TextBoxBase textBoxBase = inputElement as System.Windows.Controls.Primitives.TextBoxBase;
                    if (textBoxBase != null)
                    {
                        if (!textBoxBase.AcceptsReturn)
                            MoveFocus_Next(textBoxBase);
                        return;
                    }
                    if (
                        MoveFocus_Next(inputElement as ComboBox)
                        ||
                        MoveFocus_Next(inputElement as Button)
                        ||
                        MoveFocus_Next(inputElement as DatePicker)
                        ||
                        MoveFocus_Next(inputElement as CheckBox)
                        ||
                        MoveFocus_Next(inputElement as DataGrid)
                        ||
                        MoveFocus_Next(inputElement as TabItem)
                        ||
                        MoveFocus_Next(inputElement as RadioButton)
                        ||
                        MoveFocus_Next(inputElement as ListBox)
                        ||
                        MoveFocus_Next(inputElement as ListView)
                        ||
                        MoveFocus_Next(inputElement as PasswordBox)
                        ||
                        MoveFocus_Next(inputElement as Window)
                        ||
                        MoveFocus_Next(inputElement as Page)
                        ||
                        MoveFocus_Next(inputElement as Frame)
                    )
                        return;
                }
            }
        }
    }
    

相关问题