Я пытаюсь создать поле ввода текста с функцией автозаполнения. Список доступных опций огромен (50 000+), и их нужно будет запросить в TextChanged (после ввода первых 3 символов).
У меня есть 99% -ное рабочее решение с TextBox, устанавливающее AutoCompleteCustomSource для моего нового AutoCompleteStringCollection в событии TextChanged, но это приводит к случайным нарушениям доступа к памяти из-за хорошо задокументированной ошибки в базовой реализации AutoComplete ...
Microsoft Служба поддержки говорит: «Не изменяйте список кандидатов для автозаполнения динамически во время ключевых событий» ...
В этих потоках есть несколько предложений о том, как предотвратить исключения, но, похоже, ничто не устраняет их полностью, поэтому я ищу альтернативу. пытался переключиться на решение на основе ComboBox, но не могу заставить его вести себя так, как я хочу.
После того, как пользователь вводит третий символ, я обновляю DataSource ComboBox, но первый элемент выбирается автоматически. Пользователь не может продолжать вводить оставшуюся часть имени.
Элементы ComboBox не отображаются, пока пользователь не щелкнет треугольник, чтобы развернуть список.
Если пользователь выбирает введенный текст и начинает печатать, я устанавливаю для DataSource значение null, чтобы удалить список предложений. При этом курсор помещается в начало текста, поэтому их символы появляются в совершенно неправильном порядке!
Мой взгляд:
public event EventHandler SearchTextChanged;
public event EventHandler InstrumentSelected;
public Instrument CurrentInstrument
{
get { return comboBoxQuickSearch.SelectedItem as Instrument; }
}
public IEnumerable<Instrument> Suggestions
{
get { return comboBoxQuickSearch.DataSource as IEnumerable<Instrument>; }
set
{
comboBoxQuickSearch.DataSource = value;
comboBoxQuickSearch.DisplayMember = "Name";
}
}
public string SearchText
{
get { return comboBoxQuickSearch.Text; }
}
private void comboBoxQuickSearch_TextChanged(object sender, EventArgs e)
{
if (SearchTextChanged != null)
{
SearchTextChanged(sender, e);
}
}
private void comboBoxQuickSearch_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && InstrumentSelected != null)
{
InstrumentSelected(sender, e);
}
}
Мой ведущий:
private void SearchTextChanged(object sender, EventArgs e)
{
lock (searchLock)
{
// Do not update list of suggestions if:
// 1) an instrument has already been selected
// (the user may be scrolling through suggestion list)
// 2) a search has taken place within the last MIN_SEARCH_INTERVAL
if (DateTime.Now - quickSearchTimeStamp < minimumSearchInterval
|| (view.Suggestions != null && view.Suggestions.Any(i => i.Name == view.SearchText)))
{
return;
}
string searchText = view.SearchText.Trim();
if (searchText.Length < SEARCH_PREFIX_LENGTH)
{
// Do not show suggestions
view.Suggestions = null;
searchAgain = false;
}
// If the prefix has been entered or changed,
// or another search is needed to display the full sublist
else if (searchText.Length == SEARCH_PREFIX_LENGTH
|| searchText.Substring(0, SEARCH_PREFIX_LENGTH) != searchTextPrefix
|| searchAgain)
{
// Record the current time and prefix
quickSearchTimeStamp = DateTime.Now;
searchTextPrefix = searchText.Substring(0, SEARCH_PREFIX_LENGTH);
// Query matches from DB
IList<Instrument> matches = QueryMatches(searchText);
// Update suggestions
view.Suggestions = matches;
// If a large number of results was received, search again on the next chararacter
// This ensures the full match list is presented
searchAgain = matches.Count() > MAX_RESULTS;
}
}
}
(Бит searchAgain остался от реализации TextBox, где AutoCompleteCustomSource не всегда показывает полный список, если он содержит слишком много элементов.)
Могу ли я заставить ComboBox работать так, как я хочу, предлагая предложения по типам пользователей, учитывая мое требование запрашивать эти предложения в TextChanged?
Есть ли другая комбинация элементов управления, которую я должен использовать для лучшего взаимодействия с пользователем, например ListBox?