Фокусировка ListBoxItem в ListBox выбирает ListBoxItem над ним, а не тот, который должен быть выбран - PullRequest
0 голосов
/ 04 марта 2012

Я пытаюсь воспроизвести функцию автозаполнения, которую вы найдете на главной странице Google.Таким образом, когда вы начинаете вводить текстовое поле, вы получаете раскрывающийся список предложений и, используя клавишу со стрелкой вверх или вниз, вы можете циклически перемещаться по этому списку.Я в значительной степени там с этой функциональностью.Код, который я перечислил ниже, демонстрирует проблему.

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

В моем примере ниже, выбирается второй до последнего элемента, и я не могу понять, почему.Я жестко закодировал предложения в моем примере, поэтому нет необходимости печатать.Простое нажатие клавиши со стрелкой вверх должно продемонстрировать проблему.

<Window x:Class="MyTestApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525"
        Loaded="Window_Loaded">
    <StackPanel>
        <TextBox x:Name="nameTextBox"
                 Text="hello world!"
                 PreviewKeyDown="nameTextBox_PreviewKeyDown" />
        <ListBox x:Name="suggestionListBox"
                 DisplayMemberPath="Name"
                 SelectionChanged="suggestionListBox_SelectionChanged"
                 PreviewKeyDown="suggestionListBox_PreviewKeyDown" />
        <Label x:Name="output" />
    </StackPanel>
</Window>


using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace MyTestApplication
{
    public partial class MainWindow : Window
    {
        private const int NOT_SELECTED = -1;

        public MainWindow()
        {
            InitializeComponent();

            suggestionListBox.ItemsSource = new[] 
            {
                new { Name = "aaaaaa"},
                new { Name = "bbbbbbbb"},
                new { Name = "cccc"},
                new { Name = "ddddd"},
                new { Name = "eeeeee"},
                new { Name = "fffffffff"}
            };

            output.Content = suggestionListBox.SelectedIndex.ToString();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            nameTextBox.Focus();
        }

        private void nameTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Down)
            {
                suggestionListBox.Focus();
            }

            if (e.Key == Key.Up)
            {
                var listBoxItem = (ListBoxItem)suggestionListBox
                        .ItemContainerGenerator
                        .ContainerFromIndex(suggestionListBox.Items.Count - 1);

                var result = listBoxItem.Focus();
            }
        }

        private void suggestionListBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (    (e.Key == Key.Up && suggestionListBox.SelectedIndex == 0)
                ||  (e.Key == Key.Down && suggestionListBox.SelectedIndex == suggestionListBox.Items.Count - 1))
            {
                suggestionListBox.SelectedIndex = NOT_SELECTED;
                nameTextBox.Focus();
            }
        }

        private void suggestionListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            output.Content = suggestionListBox.SelectedIndex.ToString();
        }
    }
}

Я пытался использовать выбранный индекс в окне списка, но когда я вызываю метод фокуса в списке, выбранный индекс устанавливается в ноль.Вот почему я нахожу последний элемент списка в списке предложений и применяю к нему фокус, но он подчеркивает тот, что выше.Надеюсь, это имеет смысл.Чтобы продемонстрировать проблему, просто создайте новый проект WPF, скопируйте и вставьте приведенный выше код в MainWindow.xaml и MainWindow.Xaml.cs и запустите приложение.Все должно быть раскрыто.

Любая помощь или указание будут очень полезны.

С наилучшими пожеланиями

Мухаммед.

1 Ответ

1 голос
/ 04 марта 2012

PreviewKeyDown событие является событием tunneling, т.е. оно туннелирует от родительского элемента управления к дочернему элементу управления, и если вы не хотите, чтобы он проходил дальше, вам нужно обработать событие, установив для свойства handled свойства args значение true как это e.Handled = true.

Итак, это должно сработать для вас -

private void nameTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
   if (e.Key == Key.Down)
   {
      suggestionListBox.Focus();
   }

   if (e.Key == Key.Up)
   {
      var listBoxItem = (ListBoxItem)suggestionListBox
                        .ItemContainerGenerator
                        .ContainerFromIndex(suggestionListBox.Items.Count - 1);

      suggestionListBox.SelectedIndex = suggestionListBox.Items.Count - 1;
      listBoxItem.Focus();
      e.Handled = true;
   }
}
...