如何以编程方式将焦点设置到已具有焦点的WPF ListBox中的SelectedItem? [英] How do you programmatically set focus to the SelectedItem in a WPF ListBox that already has focus?

查看:371
本文介绍了如何以编程方式将焦点设置到已具有焦点的WPF ListBox中的SelectedItem?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们要以编程方式设置ListBoxSelectedItem,然后希望该项目具有焦点,以便箭头键相对于所选项目起作用.似乎很简单.

We want to set the SelectedItem of a ListBox programmatically and want that item to then have focus so the arrow keys work relative to that selected item. Seems simple enough.

但是问题是,如果ListBox以编程方式设置SelectedItem时已经具有键盘焦点,尽管它确实正确更新了ListBoxItem上的IsSelected属性,但没有设置键盘焦点,因此,箭头键将相对于列表中先前集中的项目移动,而不是相对于新选择的项目移动.

The problem however is if the ListBox already has keyboard focus when setting SelectedItem programmatically, while it does properly update the IsSelected property on the ListBoxItem, it doesn't set keyboard focus to it, and thus, the arrow keys move relative to the previously-focused item in the list and not the newly-selected item as one would expect.

这使用户感到困惑,因为它使使用键盘时选择似乎跳来跳去,因为它会跳回到进行编程选择之前的位置.

This is very confusing to the user as it makes the selection appear to jump around when using the keyboard as it snaps back to where it was before the programmatic selection took place.

注意:正如我所说,只有在以编程方式将SelectedItem属性设置为本身已经具有键盘焦点的ListBox属性时,才会发生这种情况.如果不是(或者,但是离开了,然后又回来),则当键盘焦点返回到ListBox时,正确的项目现在将具有预期的键盘焦点.

Note: As I said, this only happens if you programmatically set the SelectedItem property on a ListBox that already has keyboard focus itself. If it doesn't (or if it does but you leave, then come right back), when the keyboard focus returns to the ListBox, the correct item will now have the keyboard focus as expected.

以下是显示此问题的一些示例代码.为了演示这一点,请运行代码,使用鼠标在列表中选择七个"(因此将焦点放在ListBox上),然后单击测试"按钮.最后,点击键盘上的"Alt"键以显示焦点矩形.您将看到它实际上仍然在七个"上,并且如果使用向上和向下箭头,它们是相对于该行的,而不是用户期望的四个".

Here's some sample code showing this problem. To demo this, run the code, use the mouse to select 'Seven' in the list (thus putting the focus on the ListBox), then click the 'Test' button. Finally, tap the 'Alt' key on your keyboard to reveal the focus rect. You will see it's still actually on 'Seven' and if you use the up and down arrows, they are relative to that row, not 'Four' as a user would expect.

请注意,我已将按钮上的Focusable设置为false,以免在按下按钮时抢劫焦点列表框.如果我没有此功能,则单击按钮时ListBox会失去焦点,因此,当焦点返回到ListBox时,它将位于正确的项目上.

Note that I have Focusable set to false on the button as not to rob the listbox of focus when pressing it. If I didn't have this, the ListBox would lose focus when you click the button, and thus, when focus returned to the ListBox, it would be on the correct item.

XAML文件:

<Window x:Class="Test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="525" Height="350" WindowStartupLocation="CenterScreen"
    Title="MainWindow" x:Name="Root">

    <DockPanel>

        <Button Content="Test"
            DockPanel.Dock="Bottom"
            HorizontalAlignment="Left"
            Focusable="False"
            Click="Button_Click" />

        <ListBox x:Name="MainListBox" />

    </DockPanel>

</Window>

隐藏代码:

using System.Collections.ObjectModel;
using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            MainListBox.ItemsSource = new string[]{
                "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"
            };

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MainListBox.SelectedItem = MainListBox.Items[3];
        }

    }

}

注意:有些人建议使用IsSynchronizedWithCurrentItem,但是该属性会将ListBoxSelectedItem与关联视图的Current属性同步.与这个问题无关,因为这个问题仍然存在.

Note: Some have suggested to use IsSynchronizedWithCurrentItem, but that property synchronizes the SelectedItem of the ListBox with the Current property of the associated view. It isn't related to focus as this problem still exists.

我们的解决方法是暂时将焦点设置在其他位置,然后设置选定的项目,然后将焦点设置回ListBox,但这具有使我们必须使ViewModel意识到以下问题的不良影响. ListBox本身,然后根据其是否具有焦点等来执行逻辑.(即,您不想简单地说聚焦于其他位置,然后回到这里,如果'此处'还没有聚焦),您可能会从其他地方窃取它.)此外,您不能简单地通过声明性绑定来处理此问题.不用说这很丑.

Our work-around is to temporarily set the focus somewhere else, then set the selected item, then set the focus back to the ListBox but this has the undesireable effect of us having to make our ViewModel aware of the ListBox itself, then perform logic depending on whether or not it has the focus, etc. (i.e. you wouldn't want to simply say 'Focus elsewhere then come back here, if 'here' didn't have the focus already as you'd steal it from somewhere else.) Plus, you can't simply handle this through declarative bindings. Needless to say this is ugly.

然后,丑陋"的船就这样了.

Then again, 'ugly' ships, so there's that.

推荐答案

这是几行代码.如果您不希望在代码隐藏中使用它,那么我可以确定它可以打包在附加的行为中.

It's a couple lines of code. If you didn't want it in code-behind, I sure it could be packaged in a attached behaviour.

private void Button_Click(object sender, RoutedEventArgs e)
{
    MainListBox.SelectedItem = MainListBox.Items[3];
    MainListBox.UpdateLayout(); // Pre-generates item containers 

    var listBoxItem = (ListBoxItem) MainListBox
        .ItemContainerGenerator
        .ContainerFromItem(MainListBox.SelectedItem);

    listBoxItem.Focus();
}

这篇关于如何以编程方式将焦点设置到已具有焦点的WPF ListBox中的SelectedItem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆