【问题标题】:Tab between List elements WPF列表元素 WPF 之间的制表符
【发布时间】:2009-07-14 17:27:32
【问题描述】:

我有一个列表框,其中每个项目都使用文本框表示。问题是,在移动到 xaml 窗口中的下一个元素之前,我希望能够在列表框中的所有项目之间切换。

当前(和正常的 WPF 行为)是当我进入列表框时,第一个元素被突出显示,如果我再次 Tab,那么焦点将移动到该项目内的文本框。如果我再次使用 Tab,焦点将移至窗口中的下一个元素(不经过 ListBox 中的任何其他项)。

我想要的行为如下:当我进入列表框时,第一个文本框自动获得焦点(不突出显示整个项目)*。如果我再次选项卡,则列表框中的下一个文本框将获得焦点。当我在列表框中的最后一个文本框上制表时,焦点将移至下一个控件。

*我已经做了这个,我只是在这里发布它是为了解释完整的过程。

我一直在寻找解决方案,但一直找不到。

【问题讨论】:

    标签: wpf xaml


    【解决方案1】:

    这可以通过设置以下两个属性在 xaml 中完成。

        <Style TargetType="ListBox" >
            <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue" />
        </Style>
    
        <Style TargetType="ListBoxItem">
            <Setter Property="IsTabStop" Value="False" />
        </Style>
    

    完整解释见Derek Wilson's Blog post

    【讨论】:

    • 似乎比公认的答案更好的技术,我有类似的情况,它对我有用。
    • 这是一个非常好的解决方案。
    • 其中一个'WTF-would-I-do-without-StackOverflow'-时刻。谢谢,伙计!
    • 将 KeyboardNavigation.TabNavigation 属性的值设置为 Continue 就足够了。将 ListBoxItem IsTabStop 属性的值设置为 False 没有帮助。
    • @DavidCader IsTabStop=false 是必需的,否则您必须按 Tab 一次额外的时间才能在 ListBoxItem 本身中前进。
    【解决方案2】:

    编辑

    评论后,具体来说:

    private void ListBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Tab)
        {
            ListBox lb = sender as ListBox;
    
            if(lb == null) return;
    
            if(lb.SelectedIndex < lb.Items.Count - 1)
            {
                GiveItemFocus(lb, lb.SelectedIndex + 1, typeof(TextBox));
                e.Handled = true;
            }
        }
    }
    
    private void GiveItemFocus(ListBox lb, int index, Type descentdantType)
    {
        if(lb.Items.Count >= index || index < 0)
        {
            throw new ArgumentException();
        }
    
        ListBoxItem lbi = (ListBoxItem) lb.ItemContainerGenerator.ContainerFromIndex(index);
    
        lb.UnselectAll();
    
        lbi.IsSelected = true;
    
        UIElement descendant = (UIElement) FindVisualDescendant(lbi, o => o.GetType() == descentdantType);
    
        descendant.Focus();
    }
    
    private static DependencyObject FindVisualDescendant(DependencyObject dependencyObject, Predicate<bool> condition)
    {
        //implementation not provided, commonly used utility
    }
    

    e.Handled 设置为true 将确保只有您的处理程序在tab 按下时被处理,并且默认行为不会被激活。

    【讨论】:

    • 问题是,如何在列表中的项目之间移动焦点。如果我使用 UIElement 类定义的 MoveFocus 方法,那么焦点将移动到窗口中的下一个元素,而不是列表框中的下一个项目。我的问题是如何以编程方式在项目元素之间移动焦点,而不是如何触发该移动
    • 编辑了答案以提供更完整的答案。
    • 我还有一个问题。现在一切顺利,除了如果我再次进入列表框,那么第一个获得焦点的项目就是列表框中的最后一个项目。我正在尝试解决方案,但您能再帮我一次吗?
    • 可能是因为选中的项仍然是最后一项。您应该添加一个选择第一个项目的 OnGotFocus 方法,并在那里重用 GiveItemFocus 方法。
    • @kek444:你能不能把答案改成詹姆斯的答案,这让人困惑!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多