【问题标题】:How to set logical focus without giving keyboard focus?如何在不给键盘焦点的情况下设置逻辑焦点?
【发布时间】:2012-05-14 02:52:52
【问题描述】:

我如何在代码中定义容器或焦点子项的逻辑焦点,没有为其提供键盘焦点?

我只想控制当控件将通过 Tab 键获得焦点或单击没有击中子项的容器部分时,哪个子项将获得焦点,但如果没有,则不给它(或窃取)实际焦点'还没有。

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

我了解 WPF 中键盘焦点和逻辑焦点之间的区别,对于一个元素,拥有键盘焦点也意味着拥有逻辑焦点,但拥有逻辑焦点并不意味着元素拥有键盘焦点。

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

我意识到这个属性不仅在 FocusManager.IsFocusScope 设置为 true 时使用,还用于 GroupBox 等容器。

我在 WPF 焦点主题上进行了很多尝试、大量搜索和阅读,但到目前为止都没有成功,我不明白我缺少什么:

  • 调用FocusManager.SetFocusedElement也给键盘焦点,我之前暂时将我的子元素的属性Focusable更改为false,它只在之前没有孩子有焦点的第一次工作,但在孩子获得焦点后不起作用
  • 在元素或容器上处理事件 GotKeyboardFocusPreviewGotKeyboardFocus 以覆盖初始聚焦元素也不起作用,因为我无法判断焦点是通过鼠标还是通过鼠标获得的键盘,以及焦点是直接设置到子元素还是通过容器间接设置。
  • 一个例子来说明我想要实现的目标:我有一个简单的 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 上的样式和模板将项目模板中 RadioButtonIsChecked 属性绑定到其父级的 IsSelected 属性ListBoxItem,它可以工作,但对于我的具体情况,我需要将我的 RadioButtons 直接绑定到我的数据上下文的属性,我不能将它们绑定到 IsSelected 属性同时列表。

    【问题讨论】:

    • 尝试为 GroupBox 设置 FocusManager.IsFocusScope = true
    • 好问题,我自己也在寻找这个答案……

    标签: wpf xaml focus focusmanager


    【解决方案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);
        }
    

    【讨论】:

    • 正如 OP 所说,FocusManager.SetFocusedElement sometimes 还提供键盘焦点,而不仅仅是逻辑焦点。 msdn.microsoft.com/en-us/library/… "并将尝试赋予元素键盘焦点"。
    【解决方案2】:

    正如 Document 所说,FocusManager.SetFocusedElement 将在指定焦点范围内赋予指定元素逻辑焦点,并尝试赋予元素键盘焦点。

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

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

    我正在解释的说明如下:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 2011-10-08
      • 1970-01-01
      • 2020-03-23
      相关资源
      最近更新 更多