我的问题是我有两个按钮:“后退”和“前进”。
<StackPanel>
<Button Content="Backward"/>
<Button Content="Forward" IsDefault="True"/>
</StackPanel>
现在点击“Enter”按钮一切正常。用户可以单击“后退”按钮,然后使用“Enter”来使用“前进”按钮。问题是“向后”按钮被聚焦,因此“向后”按钮处理所有“进入”。所以我试图在点击后忽略“向后”按钮但仍然无法正常工作,因为StackPanel失去了它的焦点范围。将Focus Scope恢复到StackPanel的方法是什么?
用词来说: 单击后退按钮后,我想将“前进”按钮“IsDefaulted”属性设置为true。而且我不希望整个StackPanel聚焦,我只想将焦点范围更改为放置前进按钮的焦点范围。
答案 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___事件,以便代码在按钮之前看到它;并确保您的代码标记。处理为真。这样,具有焦点的按钮将永远不会看到该事件。