38

のをプログラムで設定し、SelectedItemそのListBox項目にフォーカスを当てて、選択した項目に対して矢印キーが機能するようにします。十分に単純に思えます。

ただし、問題は、プログラムでListBox設定するときに が既にキーボード フォーカスを持っている場合、 のプロパティをSelectedItem適切に更新しますが、キーボード フォーカスを設定しないため、矢印キーは、予想されるように、新しく選択されたアイテムではありません。IsSelectedListBoxItem

これは、キーボードを使用すると、プログラムによる選択が行われる前の場所に戻るため、選択が飛び跳ねるように見えるため、ユーザーにとって非常に混乱します。

注: 既に述べたように、これは、キーボード フォーカス自体が既に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同期させます。この問題はまだ存在するため、フォーカスとは関係ありません。SelectedItemListBoxCurrent

私たちの回避策は、フォーカスを一時的に別の場所に設定してから、選択した項目を設定してから、フォーカスを に戻すことですListBoxが、これには望ましくない影響があります。フォーカスがあるわけではありません (つまり、「ここ」がまだフォーカスを持っていない場合は、他の場所から盗むので、「他の場所にフォーカスしてからここに戻ってきてください」と単純に言いたくないでしょう。) さらに、これは、宣言的なバインディングを介して単純に処理することはできません。言うまでもなく、これは醜いです。ViewModelListBox

繰り返しますが、「醜い」船です。

4

5 に答える 5

57

数行のコードです。コード ビハインドで使用したくない場合は、添付の動作にパッケージ化できると確信しています。

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();
}
于 2012-05-05T15:14:32.433 に答える
2

多分添付された動作で?何かのようなもの

public static DependencyProperty FocusWhenSelectedProperty = DependencyProperty.RegisterAttached(
            "FocusWhenSelected", 
            typeof(bool), 
            typeof(FocusWhenSelectedBehavior), 
            new PropertyMetadata(false, new PropertyChangedCallback(OnFocusWhenSelectedChanged)));

private static void OnFocusWhenSelectedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var i = (ListBoxItem)obj;
        if ((bool)args.NewValue)
           i.Selected += i_Selected;
        else
           i.Selected -= i_Selected;
    }

static void i_Selected(object sender, RoutedEventArgs e)
{
    ((ListBoxItem)sender).Focus();
}

そしてxamlで

       <Style TargetType="ListBoxItem">
            <Setter Property="local:FocusWhenSelectedBehavior.FocusWhenSelected" Value="True"/>
        </Style>
于 2012-05-04T10:03:21.070 に答える
1

ListBox.SelectedItem のみを使用してから、ListBox.ScrollIntoView(listBox.SelectedItem) を使用する必要があります。

コード例:

        private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
    {

        var comparision = StringComparison.InvariantCultureIgnoreCase;
        string myString = textBox2.Text;
        List<dynamic> index = listBox.Items.SourceCollection.OfType<dynamic>().Where(x=>x.Nombre.StartsWith(myString,comparision)).ToList();
        if (index.Count > 0) { 
        listBox.SelectedItem= index.First();


            listBox.ScrollIntoView(listBox.SelectedItem);


        }

    }
于 2016-10-29T04:44:48.063 に答える
0

XAML でこれを試してみましたが、うまくいきませんでしたか?

<ListBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=YourCollectionView}" SelectedItem="{Binding SelectedItem}"></ListBox>

そしてSelectedItemプロパティ:

    private YourObject _SelectedItem;
    public YourObject SelectedItem
    {
        get
        {
            return _SelectedItem;
        }
        set
        {
            if (_SelectedItem == value)
                return;

            _SelectedItem = value;

            OnPropertyChanged("SelectedItem");
        }
    }

コードで次のことができます。

SelectedItem = theItemYouWant;

私にとって、このアプローチは常に機能します。

于 2012-05-04T10:33:13.630 に答える