のをプログラムで設定し、SelectedItem
そのListBox
項目にフォーカスを当てて、選択した項目に対して矢印キーが機能するようにします。十分に単純に思えます。
ただし、問題は、プログラムでListBox
設定するときに が既にキーボード フォーカスを持っている場合、 のプロパティをSelectedItem
適切に更新しますが、キーボード フォーカスを設定しないため、矢印キーは、予想されるように、新しく選択されたアイテムではありません。IsSelected
ListBoxItem
これは、キーボードを使用すると、プログラムによる選択が行われる前の場所に戻るため、選択が飛び跳ねるように見えるため、ユーザーにとって非常に混乱します。
注: 既に述べたように、これは、キーボード フォーカス自体が既にSelectedItem
ある にプログラムでプロパティを設定した場合にのみ発生します。ListBox
そうでない場合 (または、そうであるが離れてすぐに戻ってきた場合)、キーボード フォーカスが に戻ったときListBox
に、正しい項目に期待どおりにキーボード フォーカスが置かれるようになりました。
この問題を示すサンプル コードを次に示します。これをデモするには、コードを実行し、マウスを使用してリスト内の「7」を選択し (したがって にフォーカスを置きListBox
ます)、「テスト」ボタンをクリックしてプログラムで 4 番目の項目を選択します。最後に、キーボードの「Alt」キーをタップして、フォーカス rect を表示します。予想どおり「4」ではなく「7」のままであることがわかります。そのため、上矢印と下矢印を使用すると、「4」ではなく相対的な行「7」になり、さらに混乱しますユーザーが視覚的に見ているものと実際に焦点を合わせているものは同期していないためです。
重要:ボタンをオンに
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
同期させます。この問題はまだ存在するため、フォーカスとは関係ありません。SelectedItem
ListBox
Current
私たちの回避策は、フォーカスを一時的に別の場所に設定してから、選択した項目を設定してから、フォーカスを に戻すことですListBox
が、これには望ましくない影響があります。フォーカスがあるわけではありません (つまり、「ここ」がまだフォーカスを持っていない場合は、他の場所から盗むので、「他の場所にフォーカスしてからここに戻ってきてください」と単純に言いたくないでしょう。) さらに、これは、宣言的なバインディングを介して単純に処理することはできません。言うまでもなく、これは醜いです。ViewModel
ListBox
繰り返しますが、「醜い」船です。