【问题标题】:How can I programatically get keyboard focus on a WPF TreeViewItem?如何以编程方式将键盘焦点放在 WPF TreeViewItem 上?
【发布时间】:2011-05-11 16:06:18
【问题描述】:

我正在尝试以编程方式将键盘焦点设置为树视图项(在某些条件下)。我尝试了两种设置焦点的方法,都成功获得了TreeViewItem的焦点,但都失去了键盘焦点。

树视图绑定到一个视图模型:

<TreeView Name="solutionsModel" TreeViewItem.Selected="solutionsModel_Selected"
          ItemsSource="{Binding Items, Mode=OneWay}" />

我正在尝试通过 TreeViewItem Selected 路由事件设置焦点:

private void solutionsModel_Selected(object sender, RoutedEventArgs e)
{
    if (solutionsModel.SelectedItem != null && solutionsModel.SelectedItem is SolutionViewModel)
    {
        if (e.OriginalSource != null && e.OriginalSource is TreeViewItem)
        {
            FocusManager.SetFocusedElement(solutionsModel, e.OriginalSource as TreeViewItem);
        }
    }
}

我正在尝试将焦点集中在ControlTemplate 中的TreeViewItem

<Style d:IsControlPart="True" TargetType="{x:Type TreeViewItem}">
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TreeViewItem}">
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="true">
                        <Trigger.Setters>
                            <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
                        </Trigger.Setters>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true" />
                            <Condition Property="IsSelectionActive" Value="false" />
                        </MultiTrigger.Conditions>
                        <!--
                        <MultiTrigger.Setters>
                            <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
                        </MultiTrigger.Setters>
                        -->
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这两种方法都获得焦点,但失去键盘焦点(TreeViewItem.IsSelectionActive 为假)。窗口中没有其他元素具有我可以分辨的焦点或键盘焦点(在测试中,我在另一个面板上只有一个只读文本框可以获取焦点)。有趣的是,我可以将键盘焦点放在(已注释掉的)MultiTrigger 上,其中 IsSelectionActive 是错误的,但当然这会始终强制键盘焦点在 TreeViewItem 上。

是否有其他方法可以更好地获得键盘焦点,哪些情况下无法获得键盘焦点?

【问题讨论】:

    标签: c# wpf focus treeviewitem


    【解决方案1】:

    如果可以的话,我会将此作为评论添加,但为什么不让TreeView 处理焦点并使用TreeView.SelectedItem 抽象地处理项目。树视图将始终能够知道在键入开始时选择了哪个项目。如果选择了一个项目,则 TreeView 处于焦点位置,您可以通过管道将键盘命令传递给该项目。

    【讨论】:

    • 谢谢约书亚。在我的情况下,我试图最小化后面的代码,并让用户能够使用输入手势在树视图项上下文菜单上执行命令(无需重新选择节点)。目前,我正在扩展 TreeViewItem 以添加可用于 MultiTrigger 的 NeedsFocus 属性。
    【解决方案2】:

    可能有更好的方法,但我找到了一种方法,方法是扩展 TreeViewTreeViewItem,使其具有单独的 NeedsFocus 属性来触发何时设置焦点。

    树视图:

        <local:ModelTreeView x:Name="solutionsModel" ItemsSource="{Binding Items, Mode=OneWay}">
        </local:ModelTreeView>
    

    更新的(部分)控制模板:

    <Style d:IsControlPart="True" TargetType="{x:Type local:ModelTreeViewItem}">
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        <Setter Property="NeedsFocus" Value="{Binding NeedsFocus, Mode=TwoWay}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ModelTreeViewItem}">
                    <ControlTemplate.Triggers>
                        <Trigger Property="NeedsFocus" Value="true">
                            <Trigger.Setters>
                                <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
                            </Trigger.Setters>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    扩展类:

    public class ModelTreeView : TreeView
    {
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new ModelTreeViewItem();
        }
    
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is ModelTreeViewItem;
        }
    }
    
    public class ModelTreeViewItem : TreeViewItem
    {
        ///--------------------------------------------------------------------------------
        /// <summary>This property gets or sets whether the item needs focus.</summary>
        ///--------------------------------------------------------------------------------
        public static readonly DependencyProperty NeedsFocusProperty = DependencyProperty.Register("NeedsFocus", typeof(bool), typeof(ModelTreeViewItem));
        public bool NeedsFocus
        {
            get
            {
                return (bool)GetValue(NeedsFocusProperty);
            }
            set
            {
                SetValue(NeedsFocusProperty, value);
            }
        }
    
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new ModelTreeViewItem();
        }
    
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is ModelTreeViewItem;
        }
    }
    

    在视图模型中,只要设置了IsSelectedNeedsFocus 就会设置为 false。

    【讨论】:

      猜你喜欢
      • 2014-01-02
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-18
      • 2013-09-30
      • 1970-01-01
      • 2020-02-15
      相关资源
      最近更新 更多