我们希望以编程方式设置SelectedItem
aListBox
并希望该项目具有焦点,以便箭头键相对于该选定项目起作用。看起来很简单。
然而,问题是如果在以编程方式ListBox
设置时已经具有键盘焦点SelectedItem
,虽然它确实正确更新了IsSelected
上的属性ListBoxItem
,但它没有将键盘焦点设置为它,因此,箭头键相对于先前聚焦的项目移动列表,而不是人们期望的新选择的项目。
这对用户来说非常混乱,因为它使选择在使用键盘时看起来会跳来跳去,因为它会快速回到编程选择发生之前的位置。
注意:正如我所说,这只发生在您以编程方式将SelectedItem
属性设置在ListBox
本身已经具有键盘焦点的 a 上时。如果它没有(或者如果它有但你离开了,那么马上回来),当键盘焦点返回到 时ListBox
,正确的项目现在将按预期获得键盘焦点。
这是一些显示此问题的示例代码。为了演示这个,运行代码,使用鼠标在列表中选择“Seven”(从而将焦点放在 上ListBox
),然后单击“Test”按钮以编程方式选择第四项。最后,点击键盘上的“Alt”键以显示焦点矩形。您会看到它仍然在“七”上,而不是您所期望的“四”,因此,如果您使用向上和向下箭头,它们是相对行“七”,而不是“四”,进一步混淆用户,因为他们在视觉上看到的内容和实际关注的内容不同步。
重要提示:请注意,我已在按钮上
Focusable
设置为。false
如果我没有,当您单击它时,它会获得焦点并且ListBox
会失去焦点,从而掩盖了问题,因为当 aListBox
重新获得焦点时,它会正确聚焦选定的ListBoxItem
. 问题是当 aListBox
已经具有焦点并且您以编程方式选择ListBoxItem
.
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
,但该属性将SelectedItem
的ListBox
与Current
关联视图的属性同步。它与焦点无关,因为这个问题仍然存在。
ListBox
我们的解决方法是暂时将焦点设置在其他地方,然后设置所选项目,然后将焦点设置ViewModel
回ListBox
不是它有焦点,等等(即你不想简单地说'焦点在别处然后回到这里,如果'这里'没有焦点,因为你会从其他地方偷走它。)另外,您不能简单地通过声明性绑定来处理这个问题。不用说这是丑陋的。
再说一次,“丑陋”的船,就是这样。