如何以编程方式将键盘焦点放在 WPF TreeViewItem 上?

发布于 2024-11-06 08:01:46 字数 2741 浏览 5 评论 0原文

我正在尝试以编程方式将键盘焦点设置为树视图项(在某些条件下)。我尝试了两种设置焦点的方法,这两种方法都成功获得了 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 为 false)。我可以告诉窗口中的其他元素没有焦点或键盘焦点(在测试中,我在另一个面板上只有一个可以获得焦点的只读文本框)。有趣的是,我可以将键盘焦点放在(注释掉的)MultiTrigger 上,其中 IsSelectionActive 为 false,但这当然会强制键盘焦点放在 TreeViewItem 上随时。

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

I'm trying to programatically set keyboard focus to a tree view item (under certain conditions). I've tried 2 methods of setting focus, both of which successfully obtain focus on the TreeViewItem, but lose keyboard focus.

The tree view is bound to a view model:

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

I'm trying to set focus via the TreeViewItem Selected routed event:

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);
        }
    }
}

I'm trying to set focus on the TreeViewItem in the ControlTemplate:

<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>

Both of these methods get focus, but lose keyboard focus (TreeViewItem.IsSelectionActive is false). No other element in the window has focus or keyboard focus that I can tell (in a test, I only have one read only textbox on another panel that could get focus). Interestingly, I can get keyboard focus on the (commented out) MultiTrigger where IsSelectionActive is false, but of course that forces keyboard focus on the TreeViewItem at all times.

Is there another way to have a better chance of getting keyboard focus, and what are some conditions where keyboard focus cannot be obtained?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独行侠 2024-11-13 08:01:46

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

I'd add this as a comment if I could but, why not just have the TreeView handle the focus and work with the item abstractly using the TreeView.SelectedItem. The tree view would always be able to know which item was selected when the typing started. If an item was selected then the TreeView is in focus and you can pipe the keyboard commands through to the item.

残月升风 2024-11-13 08:01:46

可能有更好的方法,但我找到了一种通过扩展 TreeView 和 TreeViewItem 来实现此目的的方法,以在以下情况下触发单独的 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;
    }
}

在视图模型中,每当设置 IsSelected 时,NeedsFocus 都会设置为 false。

There are probably better ways, but I found a way to do this by extending TreeView and TreeViewItem, to have a separate NeedsFocus property to trigger when to set focus.

The tree view:

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

The updated (partial) control template:

<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>

The extended classes:

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;
    }
}

In the view model, NeedsFocus is set to false whenever IsSelected is set.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文