У меня есть комбобокс на С#, и я хочу использовать с ним автоматически полные предложения, однако я хочу иметь возможность изменять автоматически заполненные записи по типу пользователя, потому что допустимые допустимые записи слишком многочисленны, чтобы заполнить AutoCompleteStringCollection
при запуске.
В качестве примера предположим, что я разрешаю пользователю вводить имя. У меня есть список возможных первых имен ( "Joe" , "John" ) и список фамилий ( "Bloggs", "Smith" ), но если у меня будет тысяча, то это будет миллион возможных строк - слишком много, чтобы добавить автозаполнение. Поэтому сначала я хочу иметь только первые имена в качестве предложений ( "Joe" , "John" ), а затем, как только пользователь набрал первое имя ( "Joe" ), я хочу удалить существующие автоматически завершенные записи и заменить их с новым набором, состоящим из выбранного первого имени, за которым следуют возможные фамилии ( "Joe Bloggs", "Joe Smith" ). Для этого я попробовал следующий код:
void InitializeComboBox()
{
ComboName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
ComboName.AutoCompleteSource = AutoCompleteSource.CustomSource;
ComboName.AutoCompleteCustomSource = new AutoCompleteStringCollection();
ComboName.TextChanged += new EventHandler( ComboName_TextChanged );
}
void ComboName_TextChanged( object sender, EventArgs e )
{
string text = this.ComboName.Text;
string[] suggestions = GetNameSuggestions( text );
this.ComboQuery.AutoCompleteCustomSource.Clear();
this.ComboQuery.AutoCompleteCustomSource.AddRange( suggestions );
}
Однако это не работает должным образом. Кажется, что вызов Clear() заставляет автокомпьютер "выключить", пока в поле со списком не появится следующий символ, но, разумеется, когда появится следующий символ, вышеуказанный код снова вызовет Clear(), поэтому пользователь никогда фактически видит автоматическую полную функциональность. Это также приводит к тому, что все содержимое поля со списком становится выбранным, поэтому между каждым нажатием клавиши вы должны отменить выбор существующего текста, что делает его непригодным. Если я удалю вызов Clear(), то автозаполнение работает, но кажется, что вызов AddRange()
не имеет никакого эффекта, потому что новые предложения, которые я добавляю, не отображаются в раскрывающемся списке автоматического завершения.
Я искал решение этого и видел разные вещи, но я не могу заставить их работать - либо автоматическая полная функциональность оказывается отключенной, либо новые строки не отображаются. Вот список вещей, которые я пробовал:
- Вызов
BeginUpdate()
перед изменением строк иEndUpdate()
после. - Вызов
Remove()
для всех существующих строк вместо Clear(). - Удаление текста из выпадающего списка при обновлении строк и добавлении его обратно.
- Установка
AutoCompleteMode
в "None", когда я меняю строки, и затем снова вернусь к "SuggestAppend". - Приобретение события
TextUpdate
илиKeyPress
вместоTextChanged
. - Каждый раз заменяя существующий
AutoCompleteCustomSource
на новыйAutoCompleteStringCollection
.
Ни одна из них не помогла, даже в различных комбинациях. Spence предложил, чтобы я попытался переопределить функцию ComboBox
, которая получает список строк для автоматического завершения. Используя рефлектор, я нашел несколько методов в классе ComboBox
, которые выглядят многообещающими - GetStringsForAutoComplete()
и SetAutoComplete()
, но они оба являются частными, поэтому я не могу получить к ним доступ из производного класса. Я больше не мог этого делать.
Я попробовал заменить ComboBox
на TextBox
, потому что интерфейс автозаполнения один и тот же, и я обнаружил, что поведение немного отличается. С TextBox
он работает лучше, поскольку часть Append автозаполнения работает правильно, но в разделе "Предложение" нет - окно предложений кратковременно вспыхивает, а затем сразу исчезает.
Итак, я подумал: "Хорошо, я буду жить без функциональности" Предложить "и просто использовать" Добавить "), однако, когда я устанавливаю AutoCompleteMode
в Append, я получаю исключение нарушения доступа. То же самое происходит и с предложением - единственный режим, который не генерирует исключений, - это SuggestAppend
, даже несмотря на то, что часть предложения не ведет себя правильно.
Я думал, что при использовании управляемого кода на С# было невозможно получить исключения нарушения прав доступа. Avram предложил использовать "блокировку", чтобы исправить это, но я не знаю, что я должен заблокировать - единственное, что имеет член SyncRoot, - это AutoCompleteStringCollection
и блокировка, которая не препятствует исключениям нарушения доступа. Я также попытался заблокировать ComboBox
или TextBox
, но это тоже не помогло. Как я понимаю, блокировка только предотвращает другие блокировки, поэтому, если базовый код не использует блокировку, то мой использование этого не будет иметь никакого значения.
Итогом всего этого является то, что я не могу использовать TextBox
или ComboBox
с динамическим автоматическим завершением. Кто-нибудь знает, как я могу это достичь?
Обновление:
У меня все еще нет работы, но я узнал еще кое-что. Возможно, некоторые из них будут вдохновлять кого-то другого на то, чтобы придумать решение.
Я попробовал заменить ComboBox
на TextBox
, потому что интерфейс автозаполнения один и тот же, и я обнаружил, что поведение немного отличается. С TextBox
он работает лучше, поскольку часть Append автозаполнения работает правильно, но в разделе "Предложение" нет - окно предложений кратковременно вспыхивает, а затем сразу исчезает.
Итак, я подумал: "Хорошо, я буду жить без функции" Предложить "и просто использовать Append вместо этого", однако, когда я устанавливаю AutoCompleteMode
в Append, я получаю исключение нарушения доступа. То же самое происходит и с предложением - единственный режим, который не генерирует исключений, - это SuggestAppend
, даже несмотря на то, что часть предложения не ведет себя правильно.
Я думал, что при использовании управляемого кода С# было исключено исключение из-за нарушения прав доступа, но в любом случае результат заключается в том, что я не могу использовать TextBox
или ComboBox
с любым типом динамического автоматическое завершение. Кто-нибудь знает, как я могу это достичь?
Обновление 2:
Попробовав различные другие вещи, такие как изменение автозаполнения в рабочем потоке и использование BeginInvoke()
для моделирования поведения типа PostMessage(), я, наконец, сдался и только что реализовал свой собственный автоматический полный раскрывающийся список, используя окно списка. Это гораздо более отзывчивое, чем встроенное, и я потратил меньше времени на это, чем на попытку заставить встроенный работать, поэтому урок для всех, кто хочет этого поведения, - вам, вероятно, лучше реализуя его самостоятельно.