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