web-dev-qa-db-de.com

Zum nächsten Steuerelement gelangen Sie mit der Eingabetaste in WPF

Ich möchte zum nächsten Steuerelement wechseln, wenn ich in einer WPF-MVVM-Anwendung die Eingabetaste anstelle der Tabulatortaste drücke. Wie kann ich das erreichen?

30
Kishore Kumar

Wenn Sie möchten, dass es nur für einige Textfelder funktioniert, ist Jays Antwort am besten. 

Wenn Sie möchten, dass Ihre gesamte Anwendung auf diese Weise funktioniert, ist makwana.as Antwort besser, kann jedoch verbessert werden. 

Unten ist meine Modifikation von makwana.as Antwort , die ich in zahlreichen Anwendungen verwendet habe. Es enthält auch Unterstützung für den Übergang zum nächsten Steuerelement über die Eingabetaste, wenn das aktive Steuerelement ein Kontrollkästchen ist. Anstatt die Tag-Eigenschaft zu verwenden, um zu entscheiden, ob der Fokus verschoben werden soll oder nicht, habe ich die AcceptsReturn-Eigenschaft des Textfelds verwendet. Ich habe dies getan, weil es standardmäßig auf "false" gesetzt ist und nur in mehrzeiligen Textfeldern auf "true" gesetzt wird. In diesem Fall soll der Fokus ohnehin nicht zum nächsten Steuerelement wechseln.

Deklarieren Sie diese Ereignishandler im OnStartup-Void von App.xaml

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

Hier sind die restlichen Methoden, die erforderlich sind, damit es anwendungsübergreifend funktioniert.

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

Bearbeiten

Ich habe den Code aktualisiert, um den Tastenanschlag als gehandhabt zu markieren, wenn die Bewegung erfolgreich war, und das Kontrollkästchen zu aktivieren, da der Schlüssel gehandhabt wurde und ihn nicht mehr erreichen wird.

26
StillLearnin

Unten ist eine angefügte Eigenschaft, die ich gerade für dieses verwendet habe.

Erstens, Beispielverwendung:

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

(Die Benutzeroberfläche ist der Namespace-Alias, für den ich Folgendes definiert habe.)

Die angefügte Eigenschaft:

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

Sie sagten auch "anstelle von Tab", also frage ich mich, ob Sie die Möglichkeit, Tab auf die übliche Weise zu verwenden, unterdrücken wollen. Ich würde davon abraten, da dies ein allgemein bekanntes Paradigma ist. Wenn dies jedoch der Fall ist, können Sie in der angefügten Eigenschaft einen PreviewKeyDown -Handler hinzufügen, nach dem Tabulator suchen und Handled = true für die Ereignisargumente festlegen.

41
Jay

beispiellösung: Verwenden von PreviewKeyDown im Stapelbereich. Die Vorschau ... ist eine Blase, damit das Ereignis auf einer höheren Ebene gehandhabt werden kann. Möglicherweise müssen Sie dies für verschiedene Elementtypen unterschiedlich behandeln. Die Schaltfläche sollte die Eingabetaste beibehalten und den Fokus nicht auf die Eingabetaste ändern. 

Hier ist der Xaml:

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

Und hier ist der Code dahinter:

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

Dies ist nur eine Sandbox zum Proof of Concept.

Happy Coding ...

11
Paul Matovich

Hoffe diese Hilfe: benutze 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
MasterLuV

Schreiben Sie diesen Code in das Onstartup-Ereignis Ihrer Anwendungsdatei

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

definieren Sie dann TextBox_KeyDown als 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

Ich habe die "tag" -Eigenschaft des Textfelds für das Verschieben des Fokus verwendet. Das heißt, wenn Sie nach einiger Zeit nicht zum nächsten Steuerelement wechseln möchten, drücken Sie die Eingabetaste (im Falle eines mehrzeiligen Textfelds, in dem die Eingabe erforderlich ist, um eine neue Zeile zu erstellen). Setzen Sie die Tag-Eigenschaft einfach auf 1. 

3
makwana.a

Zuerst wurde ein Auslöser für jedes Element hinzugefügt, das aufgerufen wird, wenn PreviewKeyDown ausgelöst wird. Fügen Sie außerdem die Abhängigkeitseigenschaft hinzu und binden Sie FrameworkElement, auf die Sie den Fokus legen möchten. Stellen Sie im Trigger die Einstellung Focus für das gebundene Element ein.

1
Anatolii Gabuza

Code-Behind verwenden:

Ich habe mir den folgenden Code ausgedacht. Beachten Sie, dass e.Handled nicht gesetzt ist. MoveFocus_Next gibt auch nicht zurück, ob der Verschiebungsfokus erfolgreich war, sondern, wenn das Argument nicht null ist. Sie können Steuerelementtypen hinzufügen oder entfernen, um sie bei Bedarf zu handhaben. Der Code wurde für das MainWindow der Anwendung geschrieben, behandelt aber auch andere Fenster. Sie können den Code für den Aufruf auch vom Ereignis App_Startup aus anpassen.

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