Вы можете установить 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);
}