ListBox
のSelectedItem
をプログラムで設定し、その項目にフォーカスを当てて、矢印キーがその選択された項目に対して相対的に機能するようにします。シンプルだと思われる。フォーカスが既に設定されているWPF ListBoxのSelectedItemにプログラムでフォーカスを設定するにはどうすればよいですか?
プログラムでSelectedItem
を設定するときListBox
はすでにそれが正しくListBoxItem
にIsSelected
プロパティを更新しない一方で、それがそれにないセットのキーボードフォーカスを行い、これにより、矢印キー、キーボードフォーカスを持っている場合、問題はしかし、ですリスト内の以前にフォーカスされたアイテムに相対的に移動し、新しく選択されたアイテムは期待通りに移動しません。
これは、キーボードを使用しているときに選択がプログラム選択が行われる前の位置にスナップバックするときにジャンプするように見えるため、ユーザーにとって非常に混乱します。
注:前述のように、キーボードフォーカスが既に設定されているListBox
に、SelectedItem
プロパティをプログラムで設定した場合のみ、これが発生します。表示されない場合(または終了していても戻ってきた場合)、キーボードのフォーカスがListBox
に戻ると、正しい項目にキーボードのフォーカスが正しく設定されるようになります。
ここに、この問題を示すサンプルコードがあります。これをデモするには、コードを実行し、マウスを使用してリスト内の「セブン」を選択し(ListBox
にフォーカスを当てる)、「テスト」ボタンをクリックします。最後に、キーボードの「Alt」キーをタップして、フォーカス矩形を表示します。あなたはそれがまだ実際には 'セブン'であることがわかります。上向き矢印と下向き矢印を使用すると、それらはその行に相対的であり、ユーザーが期待するように '4'ではありません。
Focusable
は、フォーカスのリストボックスを押したときに、リストボックスを奪わないように、ボタン上にfalse
に設定されています。私がこれを持っていなかった場合、ListBox
はボタンをクリックするとフォーカスが失われ、フォーカスがリストボックスに戻ったときに正しい項目になります。
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
を使用することを示唆しているが、そのプロパティは、関連のCurrent
プロパティでListBox
のSelectedItem
を同期させますビュー。この問題は依然として存在するため、フォーカスには関係しません。
私たちの仕事の周りには、一時的にどこかにフォーカスを設定することで、その後、バックListBox
にフォーカスを設定するが、これは私たちがListBox
自身の私達のViewModel
に認識させることの望ましくない効果があり、その後、選択した項目を設定し、フォーカスを持っているかどうかに応じてロジックを実行します(つまり、「ここでは他の場所にフォーカスしてここに戻ってください」と言いたいとは思わないでしょう。また、宣言的なバインディングによってこれを処理することはできません。言うまでもなく、これは醜いです。
もう一度、「醜い」船は、そうです。
ContainerFromItemは、コンテナがまだ生成されていない場合はnullを返します。コンテナがまだ生成されていない場合は、仮想化されたリストの場合で、項目はオフスクリーンです。さらに、バインドから値を設定しようとすると、ListBoxへのアクセス権がないため、バインドされません。 (続き...) – MarqueIV
a)コントロールにフォーカスがあって(テストが簡単)、b)変更が来ていない限り、コントロールが盲目的にキーボードフォーカスをListBoxItemに設定しないように、そうでなければ、マルチセレクトモードではフォーカスを別のコントロール(ケースa)から盗んだり、現在のフォーカスをフォーカスしたりすることができます(ケースb)。その行は通常はキーボードのフォーカスを保持する必要がありますが、新しいSelectedItemが設定されていれば、それは奇妙な動作を引き起こします。 – MarqueIV
実際、2番目の考えでは、私は上記のケース「B」の回避策があると思います。あなたは言ったように添付された動作を作成しますが、XAMLで直接設定しないでください。代わりに、ViewModelにプロパティを作成し、その動作をバインドします。そうすれば、聞く人を知る必要はありません。次に、選択した項目をコードの背後から設定する直前に、動作を有効にして項目を選択し、再度動作を無効にします。これは上記の 'B'に対応します。 (もちろん「A」が必要です。)完全ではありませんが、私はこの道を私に導いてくれました。 – MarqueIV