IsDefault and FocusScope recovery

本文关键字:recovery FocusScope and IsDefault | 更新日期: 2023-09-27 17:51:26

我的问题是我有两个按钮:"后退"answers"前进"。

  <StackPanel>
            <Button Content="Backward"/>
            <Button Content="Forward" IsDefault="True"/>
        </StackPanel>

现在,当"进入"按钮点击一切工作正常。有一个可能的流程,用户点击后退按钮,然后想要使用"进入"来使用"前进"按钮。问题是"后退"按钮是集中的,所以"后退"按钮处理所有的"进入"。所以我试着在点击后取消"后退"按钮,但它仍然不起作用,可能是因为StackPanel失去了它的焦点范围。恢复焦点范围到StackPanel的方法是什么?

依次为:点击后退按钮后,我想将"前进"按钮的"isdefault"属性设置为true。我不想让整个StackPanel聚焦,我只想将焦点范围更改为Forward按钮所在的焦点范围

IsDefault and FocusScope recovery

你可以做不同的事情来实现你正在寻找的东西。然而,这些都会以某种方式影响用户体验,这可能是可取的,也可能不是可取的。

  • 你可以为点击"后退"按钮编写一个处理程序,它将焦点设置为"前进"按钮。这样做的缺点是,用户不能选择"后退"按钮,并按空格键多次激活它。

    Xaml:

    <Button Content="Backward" Click="Button_Click" />
    <Button x:Name="ForwardButton" Content="Backward" />
    
    代码:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ForwardButton.Focus();
    }
    
  • 另一个选项是将"向后"设置为不可聚焦。这意味着用户根本不能通过键盘到达按钮,他们被迫使用鼠标来激活它(使应用程序更难访问,可能不好)。

    <Button Content="Backward" Focusable="False" />
    
  • 或者,您可以将"后退"按钮设置为不处理返回/进入键。当点击它时,它仍然会被聚焦,并且在那个点之后按空格键仍然会激活它。但是,按enter键将被忽略,允许您的默认按钮拾取它。这可能会让用户感到困惑,因为他们关注的按钮并不是被激活的按钮。事实上,我对此进行了测试,在我点击"向后"(我使用的是Aero主题)后,两个按钮在视觉上似乎同时聚焦。

    <Button Content="Backward" KeyboardNavigation.AcceptsReturn="False" />
    
  • 另一种解决方案是使用PreviewKeyDown处理程序直接在代码中手动处理按键并执行所需的操作,正如Toby Crawford的答案所建议的那样。它需要更多的手工工作,但允许您完全控制发生的事情。有了这个解决方案,您需要想出一些方法来告诉用户正在发生什么。此外,还会出现一些令人困惑的流程,例如用户选择"后退"按钮,按下回车键,然后激活"前进"按钮。你需要考虑这样的事情

基本上,它归结为期望的用户体验。在这种情况下,你必须决定哪些用户输入流更重要,而代价是那些不太重要的输入流可能无法按预期工作。

WPF中的焦点管理非常复杂 1 2。基本上,您可以做任何您想做的事情(无论它对用户是否有意义),因此它确实有助于规划应用程序的整体焦点流。你应该考虑阅读一下WPF中的焦点和键盘焦点是如何工作的。

如果你想要停止后退键被按下,当它有焦点和回车键被按下时,你可以拦截回车键并标记事件为已处理。

例如:

<StackPanel PreviewKeyDown="HandleKeyPress">
    <Button x:Name="BackwardButton" Content="Backward" Click="GoBack" />
    <Button x:Name="ForwardButton" Content="Forward" Click="GoForward" />
</StackPanel>

后面有以下代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void GoForward(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("Forward");
    }
    private void GoBack(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("Backward");
    }
    private void HandleKeyPress(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            this.ForwardButton.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
            e.Handled = true;
        }
        if (e.Key == Key.Back)
        {
            this.BackwardButton.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
            e.Handled = true;
        }
    }
}

这意味着每当StackPanel的子元素有焦点并且按下一个键时,你就会得到一个更改来拦截该事件的流。

在我的例子中,如果键是Enter,那么Forward按钮将被点击;如果按下后退键,则单击后退键。

这意味着即使键盘焦点在后退键上,你按回车键;将调用GoForward()方法,而不是GoBack()方法。

关键是处理Preview___事件,这样你的代码就能在按钮之前看到它;并确保你的代码标记是真实的。这样,有焦点的按钮将永远不会看到事件。