在焦点和键盘导航方面,我看到了奇怪的行为。在下面的示例中,我有一个简化的ItemsControl,它已经模板化,以便显示绑定到ItemsSource的CheckBoxes列表。
<ItemsControl FocusManager.IsFocusScope="True"
ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
由于某些奇怪的原因, FocusManager.IsFocusScope =“True”分配导致在通过鼠标单击选中复选框时无法设置键盘焦点,并且当a时,焦点会跳出ItemsControl使用键盘上的空格键选中复选框。这两个症状似乎都指向选中复选框时发生了一些奇怪的导航,但我很难找到它的底部。
如果我使用此方法将可视树中的任何父元素设置为焦点范围,则会出现此问题。如果我删除了 FocusManager.IsFocusScope =“True”,那么问题就会消失。不幸的是,我在一个更大的项目中看到了这个问题,我不能仅仅删除这些焦点范围,而不必担心其他与焦点相关的后果。
有人可以向我解释我所看到的奇怪行为吗?这是一个错误还是我完全错过了什么?
答案 0 :(得分:16)
本文非常好地解释了这一点:http://www.codeproject.com/KB/WPF/EnhancedFocusScope.aspx
FocusScope设计的内容是什么?
Microsoft在WPF中使用FocusScope 创建一个临时的辅助焦点。 WPF中的每个ToolBar和Menu都有它的 自己的重点范围。
凭借这些知识,我们可以清楚地了解到 看看为什么我们遇到这些问题:不应执行工具栏按钮 命令本身,但无论如何 在工具栏之前有焦点 点击。要做到这一点,请路由 命令忽略焦点的焦点 范围并使用'main'逻辑 转而关注。这解释了原因 路由命令在内部不起作用 重点范围。
为什么大文本框在 测试应用截图仍然 显示插入符号?我不知道 回答这个 - 但为什么不应该呢? 当然,文本框没有 键盘焦点(小文本框中) WPF重点范围有);但它 仍然有主要的逻辑焦点 活动窗口,是接收器 所有路由命令。
这部分涵盖了您所看到的行为
为什么键盘焦点移动到 选中标签时的大文本框 WPF焦点范围内的CheckBox和 按空格切换它?
嗯,这正是您的期望 当您单击菜单项或 工具栏:键盘焦点应该 回到主要焦点。所有 ButtonBase派生的控件可以做到 此
答案 1 :(得分:8)
IsEnhancedFocusScope
附加行为的完整实现:
public static class FocusExtensions
{
private static bool SettingKeyboardFocus { get; set; }
public static bool GetIsEnhancedFocusScope(DependencyObject element) {
return (bool)element.GetValue(IsEnhancedFocusScopeProperty);
}
public static void SetIsEnhancedFocusScope(DependencyObject element, bool value) {
element.SetValue(IsEnhancedFocusScopeProperty, value);
}
public static readonly DependencyProperty IsEnhancedFocusScopeProperty =
DependencyProperty.RegisterAttached(
"IsEnhancedFocusScope",
typeof(bool),
typeof(FocusExtensions),
new UIPropertyMetadata(false, OnIsEnhancedFocusScopeChanged));
private static void OnIsEnhancedFocusScopeChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) {
var item = depObj as UIElement;
if (item == null)
return;
if ((bool)e.NewValue) {
FocusManager.SetIsFocusScope(item, true);
item.GotKeyboardFocus += OnGotKeyboardFocus;
}
else {
FocusManager.SetIsFocusScope(item, false);
item.GotKeyboardFocus -= OnGotKeyboardFocus;
}
}
private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
if (SettingKeyboardFocus) {
return;
}
var focusedElement = e.NewFocus as Visual;
for (var d = focusedElement; d != null; d = VisualTreeHelper.GetParent(d) as Visual) {
if (FocusManager.GetIsFocusScope(d)) {
SettingKeyboardFocus = true;
try {
d.SetValue(FocusManager.FocusedElementProperty, focusedElement);
}
finally {
SettingKeyboardFocus = false;
}
if (!(bool)d.GetValue(IsEnhancedFocusScopeProperty)) {
break;
}
}
}
}
}
在您的XAML中,您只需要设置此附加属性而不是标准IsFocusScope
属性:
<ItemsControl my:FocusExtensions.IsEnhancedFocusScope="True"
ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
它可以按预期的重点范围工作。