Подтвердить что ты не робот

Переход к следующему элементу управления нажатием клавиши Enter в WPF

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

<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 для события args.

Ответ 3

Пример решения: с помощью 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;
    }
}

Это только песочница для доказательства концепции.

Счастливое кодирование...

Ответ 4

Введите этот код в событие 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

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

Ответ 5

Надеюсь, что эта помощь: используйте 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">

Ответ 6

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

Ответ 7

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

Я придумал код ниже. Обратите внимание, что он не устанавливает 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;
            }
        }
    }
}