如何在不给键盘焦点的情况下设置逻辑焦点?

时间:2012-05-04 14:32:47

标签: wpf xaml focus focusmanager

我如何在代码中定义容器或焦点儿童的逻辑焦点,没有给予键盘焦点?

我只想控制哪个孩子会通过Tab键获得焦点或者点击没有击中孩子的容器的一部分,但是如果它没有给它(或偷窃)实际焦点已经拥有它了。

我还希望通过键盘手势选择特定的孩子或用鼠标点击它仍然是可能的。

我理解键盘焦点和逻辑焦点之间的WPF差异,以及对于元素,具有键盘焦点意味着也具有逻辑焦点的事实,但具有逻辑焦点并不意味着该元素具有键盘焦点。

我也理解附加属性FocusManager.FocusedElement定义哪个元素在可视树中具有逻辑焦点,从定义此属性的元素开始。

我已经意识到只有当FocusManager.IsFocusScope设置为true时才会使用此属性,但是对于 GroupBox 等容器也不会使用此属性。

我已经做了很多尝试,大量的搜索和阅读WPF焦点主题,但到目前为止没有成功,我不明白我错过了什么:

  • 调用FocusManager.SetFocusedElement也会给键盘焦点,我暂时将我的子元素的Focusable属性暂时更改为false,它只在第一次没有孩子聚焦之前工作,但是没有孩子得到焦点
  • 在元素或容器上处理事件 GotKeyboardFocus PreviewGotKeyboardFocus 以覆盖初始聚焦元素也不起作用,因为我无法判断焦点是通过鼠标获取还是键盘,以及焦点是直接设置为子元素还是通过容器间接设置。
  • 一个例子来说明我想要实现的目标:我有一组简单的RadioButtons,我想在代码中动态控制当用户将“tab”移动焦点到此GroupBox时,该选项将获得焦点(通常是具有isChecked=true)的选项。

    <GroupBox Header="Options" Name="myGroupBox"
              KeyboardNavigation.TabNavigation="Once" 
              KeyboardNavigation. DirectionalNavigation="Cycle" >
        <StackPanel>
            <RadioButton GroupName="g1" Name="opt1" Content="Option _1"/>
            <RadioButton GroupName="g1" Name="opt2" Content="Option _2"/>
            <RadioButton GroupName="g1" Name="opt3" Content="Option _3"/>
        </StackPanel>
    </GroupBox>
    

    最后评论,我知道如何使用 ListBox 实现动态选项列表,将列表的 selectedItem 绑定到数据上下文的属性,然后通过项目模板中 ListBoxItem 绑定 RadioButton IsChecked 属性的样式和模板到其父<的 IsSelcted 属性< strong> ListBoxItem ,它有效,但对于我的具体情况,我需要保持我的 RadioButtons 直接绑定到我的数据上下文的属性,我不能将它们绑定到IsSelected属性同时列表。

    2 个答案:

    答案 0 :(得分:1)

    我知道这是一个老问题,但希望这个答案可以帮助其他人解决类似问题。

    如果我正确理解了问题,您可以通过在GroupBox上设置FocusManager.IsFocusScope =“True”来实现所需的行为,并为RadioButton.Checked事件挂接一个事件处理程序,该事件将逻辑焦点设置为发送者事件:

    <强>的Xaml:

            <GroupBox Header="Options" Name="myGroupBox"
                  FocusManager.IsFocusScope="True"
                  RadioButton.Checked="MyGroupBox_OnChecked"
                  KeyboardNavigation.TabNavigation="Once" 
                  KeyboardNavigation.DirectionalNavigation="Cycle">
            <StackPanel>
                <RadioButton GroupName="g1" Name="opt1" Content="Option _1"/>
                <RadioButton GroupName="g1" Name="opt2" Content="Option _2"/>
                <RadioButton GroupName="g1" Name="opt3" Content="Option _3"/>
            </StackPanel>
        </GroupBox>
    

    代码背后:

        private void MyGroupBox_OnChecked(object sender, RoutedEventArgs e)
        {
            var radioB = sender as RadioButton;
            if (radioB != null)
                FocusManager.SetFocusedElement(myGroupBox, radioB);
        }
    

    答案 1 :(得分:0)

    如文档所述,FocusManager.SetFocusedElement 将在指定的焦点范围内给予指定的元素逻辑焦点,并将尝试给予元素键盘焦点。

    我遇到了同样的问题,我觉得这种给元素键盘焦点的尝试是不可预测的。在某些情况下,获得逻辑焦点的元素也会获得键盘焦点。但在其他一些情况下,它不会。我还没有弄清楚背后的确切机制。

    如果官方文件这么说,我认为可能没有“官方”的方式来实现你想要的。现在,我只是通过在设置逻辑焦点后对要保持键盘焦点的元素调用 Keyboard.Focus 来完成此操作。

    我解释的例子如下:

    private void SomeMember(){
      FocusManager.SetFocusedElement(focusScope, logicalFocus);
      Keyboard.Focus(controlMaintainingKeyboardFocus);
    }