WPF Combobox поиск скорости печати - PullRequest
0 голосов
/ 28 марта 2020

У меня есть комбинированный список WPF

<ComboBox BorderThickness="0" Name="cmb_songs_head" HorizontalAlignment="Right" SelectedItem="{Binding Path=T.SelectedSong, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=T.SelectedSet.Songs, UpdateSourceTrigger=PropertyChanged}" />

Когда выбран комбинированный список и я набираю его, он выбирается из выпадающего списка - что я и хочу. Например:

Hall
Hold
Hollow
Lead

Итак, когда я набираю H, выбирается первый элемент, Ho выбирает второй элемент, Holl выбирает третий.

Но пользователи моего программы жалуются на то, что они часто слишком медленно набирают текст и поэтому в итоге набирают Hol, который выбирает Hold, а затем l, который выбирает Lead; вместо того, чтобы видеть это как один вход для Hollow.

Есть ли способ продлить время ожидания между словами?

1 Ответ

1 голос
/ 28 марта 2020

Вы можете установить Binding.Delay при привязке ComboBox.SelectedItem.

. В следующем примере задержка привязки устанавливается равной 1500 мс. Каждое изменение цели или источника привязки, которое произошло до истечения задержки, сбрасывает таймер задержки:

<ComboBox Name="cmb_songs_head" 
          StaysOpenOnEdit="True"
          IsEditable="True"
          SelectedItem="{Binding T.SelectedSong, Delay=1500}"
          ItemsSource="{Binding T.SelectedSet.Songs}" />

Примечания

Связывание может быть упрощено до улучшенная читаемость:
ComboBox.SelectedItem связывает TwoWay по умолчанию.
UpdateSourceTrigger.PropertyChanged является триггером по умолчанию для свойств ItemsControl.


Обновление

Это поведение поиска по умолчанию. При наборе, соответствующий элемент ищется, и соответствие фактически выбирается.

Поскольку совпадение сразу назначается на ComboBox.SelectedItem, это может иметь нежелательные побочные эффекты, чтобы выбрать что-то не соответствующее. Особенно, когда выбор запускает операцию.

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

Я бы написал Attached Behavior, который прослушивает события ComboBox.PreviewTextInput и TextBoxBase.PreviewKeyUp для обработки фильтрации.
В следующем примере вместо этого обрабатываются эти события в программном коде и предполагается, что ComboBox Тип элемента string. Binding.Delay имеет значение 5 с:

Просмотр

<ComboBox ItemsSource="{Binding T.SelectedSet.Songs}" 
          SelectedItem="{Binding T.SelectedSong, Delay=5000}"
          StaysOpenOnEdit="True" 
          IsEditable="True" 
          TextBoxBase.PreviewKeyUp="EditTextBox_OnPreviewKeyUp"
          PreviewTextInput="ComboBox_OnPreviewTextInput" />

Кодовый код

private void EditTextBox _OnPreviewKeyUp(object sender, KeyEventArgs e)
{
  var editTextBox = e.OriginalSource as TextBox;
  var comboBox = sender as ComboBox;

  switch (e.Key)
  {
    case Key.Back:
    {
      MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
      int selectionStart = comboBox.SelectedItem == null
        ? editTextBox.CaretIndex
        : Math.Max(0, editTextBox.SelectionStart - 1);
      int selectionLength = comboBox.SelectedItem == null 
        ? 0 
        : editTextBox.Text.Length - selectionStart;
      editTextBox.Select(selectionStart, selectionLength);
      break;
    }
    case Key.Space:
    {
      MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
      break;
    }
    case Key.Delete:
    {
      int currentCaretIndex = editTextBox.CaretIndex;
      MainWindow.FilterComboBoxItemsSource(sender as ComboBox, editTextBox.Text, editTextBox);
      editTextBox.CaretIndex = currentCaretIndex;
      break;
    }
  }
}

private void ComboBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
  e.Handled = true;

  var editTextBox = e.OriginalSource as TextBox;
  string oldText = editTextBox.Text.Substring(0, editTextBox.SelectionStart);
  string newText = oldText + e.Text;

  FilterComboBoxItemsSource(sender as ComboBox, newText, editTextBox);
}

private void FilterComboBoxItemsSource(ComboBox comboBox, string predicateText, TextBox editTextBox)
{
  ICollectionView collectionView = CollectionViewSource.GetDefaultView(comboBox.ItemsSource);
  if (!string.IsNullOrWhiteSpace(predicateText) 
    && !collectionView.SourceCollection
      .Cast<string>()
      .Any(item => item.StartsWith(predicateText, StringComparison.OrdinalIgnoreCase)))
  {
    int oldCaretIndex = editTextBox.CaretIndex == editTextBox.Text.Length
      ? predicateText.Length
      : editTextBox.CaretIndex;
    editTextBox.Text = predicateText;
    editTextBox.CaretIndex = oldCaretIndex;
    return;
  }

  collectionView.Filter = item => (item as string).StartsWith(string.IsNullOrWhiteSpace(predicateText) 
    ? string.Empty 
    : predicateText, StringComparison.OrdinalIgnoreCase);

  collectionView.MoveCurrentToFirst();
  editTextBox.Text = collectionView.CurrentItem as string;
  editTextBox.Select(predicateText.Length, editTextBox.Text.Length - predicateText.Length);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...