WPF 选项卡键导航
Posted
技术标签:
【中文标题】WPF 选项卡键导航【英文标题】:WPF Tab Key Navigation 【发布时间】:2012-01-22 18:18:57 【问题描述】:我们有一个基于 WPF .NET 4.0 C# 的应用程序。我们从 XML 定义(不是 XAML)构建我们的用户界面,但在下面我们使用 WPF 来呈现 UI。也就是说,在运行时,我们基于 XML 定义创建 WPF UI。
标签导航有问题。我们为文本和组合框控件设置了 TabStop、TabIndex。 但是标签导航不起作用。如何使标签导航适用于此布局?
【问题讨论】:
你看过KeyboardNavigation类吗? 如何在此界面的代码隐藏中设置控件的 TabIndex 属性?你需要更清楚什么不起作用。贴一些代码。 “不工作”是什么意思?是“您按 Tab 但焦点不会移动”吗?还是它移动了,但移动错了?哪里错了? “但选项卡导航不起作用” - 你到底是什么意思?它是随机跳还是根本不跳?顺便说一句,如果你没有设置任何 TabIndex,它会按照你添加孩子的顺序跳转。 【参考方案1】:WPF 将整个 UI 树视为单个选项卡范围。它不会像您期望的那样分解成更小的区域。这包括 UserControls 中的控件。
例如,如果你有
<StackPanel>
<TextBox Name="TextBox1" />
<MyUserControl />
<TextBox Name="TextBox3" />
</StackPanel>
而MyUserControl
看起来像
<MyUserControl>
<TextBox Name="TextBox2" />
</MyUserControl>
默认选项卡循环为 TextBox1、TextBox2、TextBox3。这是因为没有定义 TabIndex 属性,所以所有控件都以默认的 Tab 键顺序运行,也就是它们添加到 UI 中的顺序。
如果您在控件上设置 TabIndex,如下所示,
<StackPanel>
<TextBox Name="TextBox1" TabIndex="1" />
<MyUserControl TabIndex="2" />
<TextBox Name="TextBox3" TabIndex="3" />
</StackPanel>
您的制表符将更改为 TextBox1、TextBox3、TextBox2。这是因为 TextBox2 没有指定 TabIndex,因此假定为默认值,并且在所有其他指定了 TabIndex 的控件循环通过之后,它会被选项卡化。
我通常解决这个问题的方法是将 UserControl 内的控件的TabIndex
绑定到 UserControl.TabIndex。
例如,将以下绑定添加到 UserControl 将使 Tab 循环再次正确
<MyUserControl>
<TextBox Name="TextBox2" TabIndex="Binding Path=TabIndex, RelativeSource=RelativeSource AncestorType=x:Type local:MyUserControl" />
</MyUserControl>
我通常更喜欢在 UserControl 的 Loaded
事件中设置此绑定,而不是必须记住在 UserControl 内的所有控件上设置此绑定。我相信还有更有效的方法可以做到这一点,但是问题出现的频率还不够高,让我坐下来花时间研究如何正确使用选项卡范围以避免这种解决方法。
【讨论】:
【参考方案2】:您应该尝试在Tree
控件或StackPanel
派生控件上设置KeyboardNavigation.TabNavigation 附加属性,以防您希望底部按钮也参与选项卡循环:
<controls:CustomStackPanel KeyboardNavigation.TabNavigation="Cycle">
<Tree>
...
</Tree>
</controls:CustomStackPanel>
您甚至可以将一种代码隐藏方法结合起来,我认为您目前正尝试使用该方法来控制 Tree 控件内的选项卡行为,以及 KeyboardNavigation.TabNavigation
来处理树控件外部的选项卡。
【讨论】:
在我的情况下,有人在一堆控件上设置了“Focusable="False"”,然后将其删除,然后将其添加到窗口(或网格,没关系)。有效!!谢谢。【参考方案3】:本身不是答案,但 WPF 选项卡非常繁琐。需要在 Xaml 中设置 TabNavigation、IsTabStop 属性并摆弄焦点范围。我花了几天时间试图单独使用 Xaml 来正确地进行选项卡。我建议从你的 XML -> WPF 模型开始,真的应该是 Xaml -> WPF!但是我想这是不可能的。
如何解决这个问题。您是否可以处理生成代码中的制表符?如果您的 WPF 用户控件是由您自己的软件从您自己的 XML 生成的,那么我建议在您的 XML 中放置一个 TabOrder 元素,然后使用它来连接 TabOut 事件。
查看以下代码示例,在代码中强制进行移动操作(类似于 Tabbing)
// Creating a FocusNavigationDirection object to perform the tab operation
// values include Next, Previous, First, Last etc...
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)
elementWithFocus.MoveFocus(request);
其次,连接到“可选项卡”控件的 KeyUp(或 PreviewKeyUp)事件,如果键是选项卡,则调用上面的代码以使焦点跳转到下一个元素。
上面的代码示例基本上会在代码中强制执行 WPF 开箱即用的操作。正如其他海报所建议的那样,我将通过您生成的 WPF 代码查看 KeyboardNavigation.IsTabStop 和 KeyboardNavigation.TabNavigation 的值
最好的问候,
【讨论】:
一般来说不确定是否要明确处理选项卡 - 这似乎有点 hacky。虽然为 MoveFocus 的东西 +1 - 我发现我需要它来处理自定义控件的 shift+tab,其中一些东西正在改变它的可见性。【参考方案4】:试试 KeyboardNavigation.TabNavigation="Once"
【讨论】:
以上是关于WPF 选项卡键导航的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin / iOS - 如何从硬件键盘禁用选项卡键码