WPF Tab键导航

15
我们有一个基于WPF .NET 4.0 C#的应用程序。我们从XML定义构建用户界面(而不是XAML),但在底层我们使用WPF来呈现UI。也就是说,在运行时,我们根据我们的XML定义创建WPF UI。
我们遇到了选项卡导航问题。我们为文本和组合框控件设置了TabStop、TabIndex,但选项卡导航不起作用。如何使此布局的选项卡导航正常工作?

enter image description here


你看过KeyboardNavigation类吗? - rfmodulator
4
你如何在此界面的代码后端设置控件的TabIndex属性?你需要更清楚地说明什么没有起作用。请发布一些代码。 - Bernard
4
“not working”是什么意思?是说“你按了Tab键但焦点没有移动”吗?还是焦点移动了,但移动的不正确?以何种方式是不正确的? - Pavel Gatilov
2
“但选项卡导航无法使用” - 您的意思是什么?它是随机跳转还是根本无法跳转?顺便说一下,如果您没有设置Tablndex,它将按照添加子元素的顺序跳转。 - Bogdan Olteanu
4个回答

39

WPF将整个UI树视为单个Tab范围。它没有分成较小的区域,如您所期望的那样。这包括UserControl内部的控件。

例如,如果您有

<StackPanel>
    <TextBox Name="TextBox1" />
    <MyUserControl />
    <TextBox Name="TextBox3" />
</StackPanel>

MyUserControl 看起来像这样

<MyUserControl>
    <TextBox Name="TextBox2"  />
</MyUserControl>

默认的选项卡顺序将是TextBox1、TextBox2、TextBox3。这是因为未定义TabIndex属性,因此所有控件都按照默认的选项卡顺序运行,即它们添加到UI中的顺序。

如果您在控件上设置了类似下面的TabIndex:

<StackPanel>
    <TextBox Name="TextBox1" TabIndex="1" />
    <MyUserControl TabIndex="2" />
    <TextBox Name="TextBox3" TabIndex="3" />
</StackPanel>

你的Tab键顺序将变为TextBox1、TextBox3、TextBox2。这是因为TextBox2没有指定TabIndex,因此默认情况下会在所有指定了TabIndex的控件循环后进行Tab键切换。

我通常的解决方法是将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内的所有控件上都要设置此绑定。我相信还有更有效的方法来完成这个任务,但是这个问题并没有经常出现,所以我没有花时间研究如何正确使用选项卡范围来避免这种解决办法。


11

如果想让底部按钮也参与Tab键顺序,可以尝试在Tree控件或派生自StackPanel的控件上设置KeyboardNavigation.TabNavigation附加属性:

<controls:CustomStackPanel KeyboardNavigation.TabNavigation="Cycle">
 <Tree>
 ...
 </Tree>
</controls:CustomStackPanel>

您甚至可以将代码后端方法与KeyboardNavigation.TabNavigation相结合,以控制树形控件内的标签行为,并处理树形控件外的标签。


我的情况是有人在一堆控件上设置了“Focusable = False”,在移除它之后,然后将其添加到窗口(或网格,无所谓)中。它奏效了!谢谢。 - Josh

6

虽然不是一个特定的答案,但WPF切换标签非常棘手。需要在Xaml中设置TabNavigation、IsTabStop属性,并调整焦点范围。我已经花了几天时间尝试只使用Xaml来正确处理切换标签。我建议从你的XML -> WPF模型开始,真正应该是Xaml -> WPF!然而,我想象这是不可能的。

那么这个解决方法怎么样?您是否能够在生成的代码中处理切换标签?如果您自己的软件从自己的XML生成WPF用户控件,那么建议在您的XML中放置一个TabOrder元素,然后使用它来连接一个TabOut事件。

查看以下代码示例,以在代码中强制执行移动操作(类似于切换标签)

// 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)事件,并如果按键是tab,则调用上述代码以导致焦点跳转到下一个元素。
上述代码示例基本上强制在代码中完成WPF应该直接完成的工作。正如其他帖子所建议的,我会浏览您生成的WPF代码,查看KeyboardNavigation.IsTabStop和KeyboardNavigation.TabNavigation的值。
此致,
最好的问候,

不确定如何在一般情况下明确处理制表符 - 这似乎有点破解。但是对于MoveFocus的加1 - 我发现我需要它来处理自定义控件的shift + tab,其中一些内容正在更改其可见性。 - JonnyRaa

1

尝试 KeyboardNavigation.TabNavigation="Once"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接