Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
简单WPF ItemsControl的奇怪焦点行为_Wpf_Focus_Itemscontrol_Itemtemplate_Keyboard Navigation - Fatal编程技术网

简单WPF ItemsControl的奇怪焦点行为

简单WPF ItemsControl的奇怪焦点行为,wpf,focus,itemscontrol,itemtemplate,keyboard-navigation,Wpf,Focus,Itemscontrol,Itemtemplate,Keyboard Navigation,当涉及到焦点和键盘导航时,我看到了奇怪的行为。在下面的示例中,我有一个简单的ItemsControl,它已模板化,因此它显示绑定到ItemsSource的复选框列表 <ItemsControl FocusManager.IsFocusScope="True" ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}"> <ItemsControl.ItemTemplate&

当涉及到焦点和键盘导航时,我看到了奇怪的行为。在下面的示例中,我有一个简单的ItemsControl,它已模板化,因此它显示绑定到ItemsSource的复选框列表

<ItemsControl FocusManager.IsFocusScope="True"
              ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

出于某种奇怪的原因,FocusManager.IsFocusScope=“True”分配会导致在通过鼠标单击选中复选框时无法设置键盘焦点,并且在使用键盘上的空格键选中复选框时,焦点会跳出ItemsControl。这两种症状似乎都表明,当选中复选框时,会出现一些奇怪的导航,但我很难弄清到底

如果使用此方法将可视化树中的任何父元素设置为焦点范围,则会出现此问题。如果我删除FocusManager.IsFocusScope=“True”,那么问题就会消失。不幸的是,我在一个更大的项目中看到了这个问题,在这个项目中,我不能只删除这些焦点范围而不担心其他与焦点相关的后果


有人能解释一下我看到的奇怪行为吗?这是一个bug还是我完全遗漏了什么?

本文对此进行了很好的解释:

聚焦镜是为什么设计的?

微软在WPF中使用FocusScope来 创建临时辅助焦点。 WPF中的每个工具栏和菜单都有自己的 自己的焦点范围

有了这些知识,我们可以清楚地 看看我们为什么会有这些问题:

工具栏按钮不应执行 命令本身,但不管是什么 在打开工具栏之前具有焦点 点击。要实现这一点,我们需要 命令从焦点忽略焦点 作用域并使用“主”逻辑 而是专注。这就解释了原因 路由命令在内部不起作用 焦点范围

为什么屏幕上的大文本框 测试应用程序截图 显示插入符号?我不知道是什么原因 答案是——但为什么不应该呢? 当然,文本框没有 键盘焦点(中的小文本框) WPF的重点范围包括:;但是它 仍然是本文的主要逻辑焦点 活动窗口和是接收器 所有路由命令的

这部分涵盖了你看到的行为

为什么键盘焦点会移到 当您使用tab键切换到 WPF焦点范围中的复选框和 按空格键切换它

这正是你所期望的 单击菜单项或菜单项时 工具栏:键盘焦点应该是 回到主要焦点。全部的 ButtonBase派生控件就可以了 这个


@梅莱克很好地解释了这个问题。请阅读这篇文章,以充分了解问题是什么以及如何解决它。我将添加文章中提到的
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>


它将按照您期望的焦点范围工作。

+1了解问题的解释。我刚刚添加了IsEnhancedFocusScope附加行为的实现。给出这个解释后,我仍然不明白的唯一一件事是,如果我再举一个例子,将一个网格设置为焦点范围,其中包含一组子对象,这些子对象是按钮和复选框,当我点击其中一个复选框时,我没有看到我在ItemsControl中看到的奇怪的失焦行为。为什么这似乎只影响ItemsControl中的复选框,这是否与ScrollViewer、ItemsPresenter等有关。。。?