从一个部分跳到另一个部分以通过 F6 键聚焦第一个控件

Jump from section to section to focus the first control via Key F6

我需要通过按 F6 从一个部分跳到另一个部分的功能。我的栏目是

  1. Menu 酒吧
  2. Button 酒吧
  3. ComboBox
  4. TabControl

我尝试从 window 实现 PreviewKeyDown-Event,但是当我手动将焦点设置在控件上时,它没有设置。

非常感谢您的回答

以下解决方案保留默认的 Tab 导航不变,因为您只需要专门针对按 F6 的自定义行为。有关类似选项卡导航解决方案的更多信息,请参阅最后一段。

如果您为 PreviewKeyDown 或特定控件上的任何其他键事件添​​加事件处理程序,则只有在相应控件具有键盘焦点时才会触发它。这就是为什么你应该在包含视图、用户控件或父级 window 上注册处理程序(对于没有焦点控件或焦点控件不是我们跟踪或添加的控件之一的情况很重要处理程序)。

<Window ...
        PreviewKeyDown="CycleFocus">

为您想要关注的 window 中的每个控件指定一个名称。

<StackPanel>
   <Menu x:Name="MyMenu">
      <MenuItem Header="Menu Item">
         <MenuItem Header="Sub Menu Item"/>
      </MenuItem>
   </Menu>
   <ComboBox x:Name="MyComboBox" ItemsSource="ABC"/>
   <TabControl x:Name="MyTabControl">
      <TabItem Header="Tab"/>
   </TabControl>
</StackPanel>

按照您希望在其中循环的顺序创建这些控件的数组。请注意,这只是一个例子来理解这个想法。您还可以仅存储控件的名称并在以后解析它们或搜索可视化树或其他任何内容。根据您的要求,有多种选择。

public partial class MainWindow
{
   private IInputElement[] FocusChain;
   
   public MainWindow()
   {
      InitializeComponent();
      
      FocusChain = new IInputElement[]
      {
         MyMenu,
         MyComboBox,
         MyTabControl
      };
   }
   
   // ...other code.
}

创建用于检测键和循环焦点的事件处理程序。

  • 首先检查是否按下了右键,否则什么都不做。
  • 如果 none 个已知控件获得焦点,则使用第一个焦点链元素。
  • 如果键盘焦点在 内,则检查每个可聚焦的项目。请注意,例如ComboBox 焦点项目可能是 ComboBoxItem,而不是 ComboBox 本身,但我们希望以同样的方式处理这种情况。
  • 如果焦点在已知元素内,则获取下一个可聚焦元素。模数 (%) 确保使用第一个元素,如果最后一个元素当前聚焦(否则索引将超出范围)。
  • 最后,将逻辑和键盘焦点设置到下一个可聚焦元素。
private void Menu_PreviewKeyDown(object sender, KeyEventArgs e)
{
   if (e.Key != Key.F6)
      return;

   var next = FocusChain[0];
   for (var i = 0; i < FocusChain.Length; i++)
   {
      if (FocusChain[i].IsKeyboardFocusWithin)
      {
         next = FocusChain[(i + 1) % FocusChain.Length];
         break;
      }
   }

   next.Focus();
   Keyboard.Focus(next);
}

如果您想使用 Tab 导航实现类似的效果,您可以这样做。

private void Menu_PreviewKeyDown(object sender, KeyEventArgs e)
{
   if (e.Key != Key.F6)
      return;

   if (Keyboard.FocusedElement is UIElement uiElement)
      uiElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}

在这种情况下,TabF6 的效果相同。请注意,在 Menu 的情况下,当 Tab 键切换时,所有 MenuItem 将一个接一个地获得键盘焦点。为了仅对整个 Menu 启用一次焦点,请设置 TabNavigation attached property to Once.

<Menu KeyboardNavigation.TabNavigation="Once">

关于逻辑和键盘焦点的更多信息,您可以参考documentation