Как программно установить фокус на SelectedItem в WPF ListBox, который уже имеет фокус?

Мы хотим программно установить SelectedItemдля ListBoxи хотим, чтобы этот элемент имел фокус, чтобы клавиши со стрелками работали относительно этого выбранного элемента. Кажется достаточно простым.

Проблема, однако, заключается в том, что если ListBoxуже имеет фокус клавиатуры при установке SelectedItemпрограммно, хотя он правильно обновляет свойство IsSelectedв ListBoxItem, он не устанавливает фокус клавиатуры на него, и, таким образом, клавиши со стрелками перемещаются относительно ранее -сфокусированного элемента в списке, а не вновь -выбранного элемента, как можно было бы ожидать.

Это очень сбивает с толку пользователя, так как кажется, что выбор прыгает при использовании клавиатуры, поскольку он возвращается туда, где он был до того, как произошел программный выбор.

Примечание. :Как я уже сказал, это происходит только в том случае, если вы программно устанавливаете свойство SelectedItemдля ListBox, у которого уже есть фокус клавиатуры. Если это не так (или если это произойдет, но вы уйдете, тогда сразу же возвращайтесь ),когда фокус клавиатуры вернется к ListBox, правильный элемент теперь будет иметь фокус клавиатуры, как и ожидалось.

Вот пример кода, показывающий эту проблему. Чтобы продемонстрировать это, запустите код, используйте мышь, чтобы выбрать «Семь» в списке (, переместив фокус на ListBox), затем нажмите кнопку «Тест». Наконец, нажмите клавишу «Alt» на клавиатуре, чтобы открыть прямоугольник фокуса. Вы увидите, что на самом деле это все еще «Семь», и если вы используете стрелки вверх и вниз, они относятся к этой строке, а не «Четыре», как ожидает пользователь.

Обратите внимание, что я установил Focusableна falseна кнопке, чтобы не лишать фокус списка при нажатии на нее. Если бы у меня этого не было, ListBoxтерял бы фокус при нажатии кнопки, и, таким образом, когда фокус возвращался бы к 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, но это свойство синхронизирует SelectedItemсвойства ListBoxсо свойством Currentсвойства ассоциированный вид. Это не связано с фокусом, так как эта проблема все еще существует.

Наша работа -состоит в том, чтобы временно установить фокус в другом месте, затем установить выбранный элемент, а затем снова установить фокус на ListBox, но это имеет нежелательный эффект, заключающийся в том, что нам приходится сообщать ViewModelо том, самого ListBox, затем выполнять логику в зависимости от того, есть ли у него фокус и т. д. (т. е. вы не хотели бы просто сказать «Сфокусируйтесь на другом месте, а затем вернитесь сюда», если «здесь» не было фокус уже как бы украл его откуда-то еще. )Кроме того, вы не можете просто справиться с этим с помощью декларативных привязок. Излишне говорить, что это некрасиво.

Опять же, «уродливые» корабли, вот что.

34
задан MarqueIV 5 May 2012 в 07:41
поделиться