IsDefault和FocusScope恢复

时间:2015-05-31 10:06:16

标签: c# wpf focus

我的问题是我有两个按钮:“后退”和“前进”。

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

现在点击“Enter”按钮一切正常。用户可以单击“后退”按钮,然后使用“Enter”来使用“前进”按钮。问题是“向后”按钮被聚焦,因此“向后”按钮处理所有“进入”。所以我试图在点击后忽略“向后”按钮但仍然无法正常工作,因为StackPanel失去了它的焦点范围。将Focus Scope恢复到StackPanel的方法是什么?

用词来说: 单击后退按钮后,我想将“前进”按钮“IsDefaulted”属性设置为true。而且我不希望整个StackPanel聚焦,我只想将焦点范围更改为放置前进按钮的焦点范围。

2 个答案:

答案 0 :(得分:1)

您可以通过不同的方式来实现您所寻找的目标。但是,这些都会以某种方式影响用户体验,这可能是也可能不是。

  • 您可以为“后退”按钮单击编写处理程序,将焦点设置为“前进”按钮。这样做的缺点是用户无法选择“后退”按钮并持续按空格键多次激活它。

    的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键将被忽略,允许您使用默认按钮来拾取它。这可能看起来让用户感到困惑,因为他们关注的按钮不是被激活的按钮。事实上,我测试了这个,当我点击“Backward”(我正在使用Aero主题)后,两个按钮似乎同时在视觉上聚焦。

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

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

WPF中的焦点管理很复杂 1 2 。您基本上可以做任何您想做的事情(无论是否对用户有意义),因此确实有助于规划应用程序的整体焦点流程。你应该考虑阅读how focus and keyboard focus work in WPF

答案 1 :(得分:0)

如果要在按下Focus并按Enter时停止按下Backward按钮,您可以截取Enter按键并将事件标记为已处理。

例如:

<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按钮;如果按下后退(退格键),则单击后退按钮。

这意味着即使键盘焦点位于“后退”按钮上并按Enter键;将调用GoForward()方法而不是GoBack()方法。

关键是要处理Preview___事件,以便代码在按钮之前看到它;并确保您的代码标记。处理为真。这样,具有焦点的按钮将永远不会看到该事件。