Переход к следующему элементу управления при нажатии клавиши Enter в WPF - PullRequest
34 голосов
/ 20 ноября 2011

Я хочу перейти к следующему элементу управления, когда нажимаю клавишу Enter вместо клавиши Tab в приложении WPF MVVM. Как мне этого добиться?

Ответы [ 7 ]

42 голосов
/ 20 ноября 2011

Ниже приведено свойство, которое я использовал только для этого.

Во-первых, пример использования:

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

Вы также сказали «вместо вкладки», поэтому мне интересно, хотите ли вы, чтобы подавить возможность использовать вкладку обычным способом. Я бы посоветовал против этого, так как это распространенная, хорошо известная парадигма, но если это так, вы можете добавить обработчик PreviewKeyDown в присоединенном свойстве, проверить ключ табуляции и установить Handled = true для Аргументы событий.

28 голосов
/ 21 июня 2012

Если вы хотите, чтобы оно работало только с несколькими текстовыми полями, Лучше всего ответ Джея .

Если вы хотите, чтобы все ваше приложение работало таким образом, makwana.a ответ лучше, но его можно улучшить.

Ниже приведена моя модификация ответа makwana.a , которую я использовал во многих приложениях.Он также включает поддержку перехода к следующему элементу управления с помощью клавиши ввода, если активным элементом управления является флажок.Вместо того чтобы использовать свойство тега, чтобы решить, должен ли фокус перемещаться, я использовал свойство AcceptsReturn текстового поля.Я сделал это, потому что по умолчанию установлено значение false и будет установлено значение true только в многострочных текстовых полях.В этом случае вы все равно не захотите, чтобы фокус переместился на следующий элемент управления при вводе.

Объявите эти обработчики событий в 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));

Вотостальные методы, необходимые для того, чтобы заставить его работать во всем приложении.

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

Редактировать

Я обновил код, чтобы пометить нажатие клавиши как обработанное, если перемещение было успешныма также переключить флажок, поскольку ключ был обработан и больше не достигнет его.

12 голосов
/ 20 ноября 2011

пример решения: использование 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;
    }
}

Это только песочница для подтверждения концепции.1010 * Счастливое кодирование ...

3 голосов
/ 18 апреля 2015

Надеюсь, что это поможет: используйте 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">
3 голосов
/ 21 ноября 2011

Напишите этот код в событии onstartup вашего файла приложения

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

затем определите подпрограмму TextBox_KeyDown как

 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

Я использовал свойство тега textbox для пропуска фокуса перемещения. т.е. если какое-то время вы не хотите переходить к следующему элементу управления при нажатой клавише ввода (в случае многострочного текстового поля, где требуется ввод для создания новой строки) Просто установите свойство тега в 1.

1 голос
/ 20 ноября 2011

Сначала произошло добавление триггера к каждому элементу, который будет вызываться при срабатывании PreviewKeyDown. Также добавьте свойство Dependency и привяжите FrameworkElement, на который вы хотите обратить внимание. В триггере задайте настройку Focus для связанного элемента.

0 голосов
/ 05 февраля 2014

Использование кода:

Я пришел с кодом ниже.Обратите внимание, что он не устанавливает 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;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...