Visual studio combobox запретить редактирование

Обновлено: 07.07.2024

Если поставить стиль csDropDownList то user может
изменить находящееся в нем текущее значение, на другую строку.
если поставить Enabled = false, то все Ок, за исключением
того что текст становиться серым и плохо читаемым.

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

используйте свойство ComboStyle:

это еще один метод, который я использую, потому что изменение DropDownSyle to DropDownList заставляет его выглядеть 3D, а иногда его просто уродливо.

вы можете предотвратить ввод пользователя, обработав KeyPress событие ComboBox, как это.

Yow может изменить стиль DropDownStyle в свойствах на DropDownList. Это не покажет текстовое поле для фильтра.

Помогите написать процедурку которая бы проверяла текст введенный в комбобкс и если у комбобкс.items нет совпадений с текстом то запрещала бы ввод. Попробовал реализовать так.

Но что у комбобокса становится странное поведение (

Ну заполняешь ты свой list совпадениями при каждом нажатии клавиши, и что дальше? Явно не хватает Combo.Items := list.

Вы не поняли что я хочу. Мне не нужно заполнять список combobox мне нужно запретить ввод данных если в списке combobox не нашлось совпадений.

Например у меня есть

Цитата (MrDmitry @ 4.4.2014, 16:07 )
Вы не поняли что я хочу.

Я понял что ты хочешь. Еще я вижу что ты уже написал. Даже если допустить, что я не разобрался, тогда объясни мне что делает с твоем коде list?

Только не забудь предусмотреть дополнительную обработку нужных клавиш (Delete и т.п.)

Цитата (Poseidon @ 4.4.2014, 21:38)
Цитата (MrDmitry @ 4.4.2014, 16:07 )
Вы не поняли что я хочу.

Я понял что ты хочешь. Еще я вижу что ты уже написал. Даже если допустить, что я не разобрался, тогда объясни мне что делает с твоем коде list?

У меня была не удачная реализация )) По моей логике должно было происходить так.
В list заносятся все значения от комбобокса в которых нашлись совпадения с введенной стройкой, соответственно если list не пустой, то продолжаем ввод, если пустой, то затираем последний введенный символ(не позволяем вводить новый) но вот логика компилятора(да и вообще логика) со мной не согласились ))

Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Возвращает или задает значение, разрешающее либо запрещающее редактировать текст в текстовом поле элемента управления ComboBox.

Значение свойства

true , если ComboBox можно редактировать; в противном случае — false . Значение по умолчанию — false .

Примеры

В следующих примерах создаются ComboBox элементы управления, содержащие изображения в виде элементов, а не текста. Если IsEditable свойство имеет значение true , то TextBox отображает значение, возвращаемое ToString методом изображения. Чтобы избежать возникновения TextBox непредвиденного текста, используйте TextSearch.Text Свойства и TextSearch.TextPath для назначения отображаемого текста.

Другим решением является использование DisplayMemberPath Свойства. Элемент управления "раскрывающийся список" ComboBox не будет отображать изображения, но будет отображать назначенный текст.

В следующем примере показано, как использовать DisplayMemberPath.

Комментарии

IsEditableСвойства и IsReadOnly определяют, как работает, ComboBox когда пользователь выполняет одно из следующих действий:

Вводит строку для выбора элемента в ComboBox .

Вводит строку, которая не соответствует элементу в ComboBox .

Выбирает часть строки, которая находится в текстовом поле.

Копирует или вставляет значение в текстовое поле.

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

IsReadOnly равно true IsReadOnly равно false
IsEditable равно true -Не удается выбрать элемент в, ComboBox введя строку.
-Невозможно ввести строку, которая не соответствует элементу в ComboBox .
— Может выбрать часть строки в ComboBox текстовом поле.
— Может скопировать строку в ComboBox текстовое поле, но не может вставить строку в ComboBox текстовое поле.
— Может выбрать элемент в, ComboBox введя строку.
— Может ввести строку, не соответствующую элементу в ComboBox .
— Может выбрать часть строки в ComboBox текстовом поле.
— Может копировать или вставлять строку в ComboBox текстовое поле.
IsEditable равно false — Может выбрать элемент в, ComboBox введя строку.
-Невозможно ввести строку, которая не соответствует элементу в ComboBox .
-Не удается выбрать часть строки в ComboBox .
-Невозможно скопировать или вставить строку в ComboBox .
— Может выбрать элемент в, ComboBox введя строку.
-Невозможно ввести строку, которая не соответствует элементу в ComboBox .
-Не удается выбрать часть строки в ComboBox .
-Невозможно скопировать или вставить строку в ComboBox .

Когда параметр равен IsEditable false , ComboBox компонент использует ContentPresenter для вывода текущего выбранного элемента; если IsEditable равно true , для TextBox этой цели используется. Обратите внимание, что TextBox отображается только обычный текст, который ComboBoxItem может включать в себя неформатированное текстовое содержимое, например изображения.

Я пытаюсь реализовать это, если пользователь выбирает (например) Value 1 в Combobox 1 , тогда Value 1 не должно быть видно, или, по крайней мере, не может быть выбрано внутри Combobox 2/3/4 / и т. д. Если Value 1 не выбрано из Combobox 1 , оно должно быть снова доступен для выбора.

У меня есть собственный класс для элементов Combobox, который выглядит так:

Эта часть моего кода выбирает значения из ячеек DataGridView и вставляет их в несколько комбинированных списков :

Затем они могут быть выбраны в моем интерфейсе, который затем считывается программой, которая затем экспортирует выбранные значения в сгенерированный файл .txt .

2 ответа

Одну проблему, которую я вижу в этой конкретной ситуации, лучше всего объяснить на примере. Допустим, есть четыре (4) ComboBoxes , и в каждом поле со списком есть четыре (4) элемента для выбора («Spalte 1», «Spalte 2», «Spalte 3» и «Spalte 4»). Далее… предположим, что пользователь выбрал «Spalte 1» в поле со списком 1, «Spalte 2» в поле со списком 2, «Spalte 3» в поле со списком 3 и «Spalte 4» в поле со списком 4…

В этой ситуации, если пользователь щелкнет любое из полей со списком . тогда . каждый ComboBox будет содержать ТОЛЬКО ОДИН (1) элемент для выбора . то есть . текущий выбранный элемент. Итак . как пользователь сможет «изменить» один из выбранных элементов поля со списком, если используются ВСЕ элементы поля со списком? Я имею в виду, что люди ДЕЙСТВИТЕЛЬНО совершают ошибки. Например, пользователь совершил ошибку и хотел поменять местами два значения поля со списком. Такой подход может привести к тупику, в котором пользователь застрянет.

Конечно… «программно» мы могли бы установить индекс поля со списком «Selected» на -1 и удалить текущий выбранный элемент и добавить его обратно в список элементов других полей со списком . однако . мы НЕ ЗНАЕМ, КОГДА это делать. Пользователь должен был бы щелкнуть кнопку или использовать какой-либо другой механизм, чтобы «сигнализировать», что он хочет «удалить» текущий выбранный элемент, и установить значение поля со списком на «пустое» значение.

К счастью, есть простое и распространенное решение. В большинстве случаев при работе с полями со списком я обычно добавляю «пустой» элемент в список элементов со списком и обычно устанавливаю его как первый элемент в списке. Мне нравится думать об этом «пустом / пустом» элементе поля со списком как о способе пользователя сказать «Я не хочу выбирать какой-либо элемент для этого поля со списком». Это интуитивно понятно для пользователя и решит описанную ранее проблему. В приведенном ниже решении используется этот подход.

Кроме того, учитывая, что каждое поле со списком будет иметь разные элементы в своем списке… тогда . каждое поле со списком должно иметь СОБСТВЕННЫЙ источник данных. Использование «одного и того же» источника данных для ВСЕХ полей со списком… не сработает. Поэтому мы будем создавать новый источник данных для каждого поля со списком всякий раз, когда пользователь изменяет ЛЮБОЕ значение поля со списком.

Я уверен, что могут быть другие, более эффективные способы достижения этой цели, так что это можно считать «хакерским» подходом, однако он сработает. Идея работает так . когда значение поля со списком изменяется, мы хотим получить список значений поля со списком, которые НЕ выбраны в данный момент. Другими словами… «доступные» элементы, которые мы МОЖЕМ выбрать. Как только у нас есть этот список . тогда мы можем перебирать каждый ComboBox и проверять его текущее выбранное значение. Если выбранное значение НЕ является «пустым» значением, то мы просто добавляем этот элемент в наш список доступных элементов, а затем устанавливаем этот источник данных поля со списком в этот список.

Например, если в поле со списком выбрано «Spalte 1»… тогда мы ЗНАЕМ, что этот элемент НЕТ в нашем списке «доступных элементов», поскольку он уже выбран в текущем поле со списком. Поэтому нам нужно добавить его в список «доступных элементов» ТОЛЬКО ДЛЯ ТОГО конкретного поля со списком. Продолжаем таким же образом для всех комбинированных списков. Особый случай - если пользователь выбрал «пустой» элемент из списка элементов. В этом случае у нас уже будет «пустой» элемент в списке «доступных элементов», и мы просто проигнорируем эти значения поля со списком, так как мы не хотим добавлять повторяющееся «пустое» значение.

Целесообразно создать специальный класс для источника данных поля со списком и использовать ваш текущий класс ComboboxItem … Я взял на себя смелость добавить несколько изменений, чтобы упростить основной код. Одно изменение касается того, что мы захотим «отсортировать» элементы List<ComboboxItem> , чтобы ВСЕ элементы поля со списком отображались в одинаковом порядке. Поскольку код будет добавлять / удалять элементы в каждое поле со списком при изменении одного из них, мы хотим поддерживать согласованный порядок для ВСЕХ элементов поля со списком, и сортировка списка каждый раз является простым решением.

Следовательно, у нас будет класс ComboboxItem , реализующий интерфейс IComparable , а затем мы сможем отсортировать List<ComboboxItem> , просто вызвав его метод Sort() . Кроме того, мы хотим переопределить метод Equals , чтобы код мог использовать метод List.Contains , чтобы видеть, есть ли конкретный ComboboxItem уже в списке. Это используется для предотвращения дублирования элементов.

И, наконец, поскольку мы хотим иметь «пустой» ComboboxItem . мы реализуем «статическое» свойство BlankComboItem , которое будет возвращать «пустой» ComboboxItem , так что его Value свойство установлено в ноль (0), а его свойство Text будет установлено в пустую строку. Этот модифицированный класс может выглядеть примерно так…

Далее мы создадим три простых метода, которые помогут в управлении полями со списком и помогут нам решить, какие значения принадлежат какому полю со списком. Первый метод GetComboList() возвращает наш список по умолчанию List<ComboboxItem> элементов поля со списком. Поскольку для каждого поля со списком нужен свой собственный источник данных, мы вызовем этот метод один раз, чтобы установить глобальный список AllItems , который мы будем использовать в следующих методах, затем мы вызовем его один раз для каждого поля со списком, чтобы изначально установить каждое поле со списком. box к одним и тем же значениям, но технически это будут «разные» списки. Этот метод может выглядеть примерно так…

Затем нам нужен метод GetCurrentSelectedItems() , который просматривает все ComboBoxes и возвращает List<ComboboxItem> всех текущих «выбранных» элементов поля со списком. Мы будем использовать этот список, чтобы получить все элементы поля со списком, которые мы МОЖЕМ использовать. Другими словами, этот метод предоставит нам список элементов, которые мы НЕ МОЖЕМ использовать, поскольку в поле со списком этот элемент уже выбран. Следует отметить, что перед вызовом этого кода мы установили глобальную переменную List<ComboBox> под названием AllCombos , которая будет содержать ВСЕ используемые ComboBoxes . Этот метод GetCurrentSelectedItems может выглядеть примерно так…

Имейте в виду, что этот метод МОЖЕТ / вернет «пустой» элемент поля со списком, поскольку для поля со списком может быть выбран «пустой» элемент.

И, наконец, мы создадим метод GetAvailableComboItems , который вернет List<ComboboxItem> , содержащий ВСЕ ComboboxItems , которые еще НЕ были выбраны ни в одном из полей со списком. Код просто просматривает список AllItems и проверяет, есть ли элемент уже в списке usedItems из вышеуказанного метода. Если элемент НЕ является используемым списком, мы добавим его в этот список «доступных элементов». Если элемент уже используется, то, очевидно, мы не хотим добавлять его в список «доступных элементов». Этот метод может выглядеть примерно так…

Чтобы собрать все это вместе, нам сначала нужно настроить глобальные переменные и все поля со списком. Это делается в событии загрузки форм и может выглядеть примерно так…

Метод SetComboBoxesSelectedIndexChanged(bool) используется для подписки / отмены подписки на каждое событие SelectedIndexChanged поля со списком. Когда поля со списком загружаются данными, устанавливается DataSource И в каждом поле со списком в качестве элемента, выбранного по умолчанию, устанавливается «пустой» элемент по умолчанию. Когда данные загружаются, нам не нужно запускать событие ComboBox_SelectedIndexChanged , и этот метод включает / выключает событие. То же самое будет применяться к самому событию SelectedIndexChanged . Код изменит источник данных И повторно установит выбранный индекс, и в этом случае это повторно запустит событие, которое нам не нужно и не нужно.

Глобальная переменная AllItems заполняется всеми ComboboxItems и будет использоваться ранее описанными методами. Кроме того, глобальный список AllCombos заполнен всеми ComboBoxes , чтобы упростить цикл по всем различным полям со списком. И, наконец, метод SetComboBoxProperties , который устанавливает свойства каждого поля со списком. Все свойства идентичны, за исключением самого ComboBox , его Name и DataSource .

И, наконец, событие / метод, объединяющий все это воедино, - это событие поля со списком SelectedIndexChanged . Мы будем использовать это же событие для ВСЕХ полей со списком. Прохождение этого метода запускает цикл foreach через каждый ComboBox . Сначала мы получаем новый список доступных элементов и берем текущий выбранный ComboboxItem для этого поля со списком. Если текущий выбранный индекс полей со списком не равен -1, это означает, что «что-то» уже выбрано, и нам нужно добавить этот элемент в список доступных элементов. Затем выполняется проверка, чтобы убедиться, что «пустой» элемент находится В списке доступных элементов, поскольку мы всегда хотим, чтобы «пустой» элемент был в списке доступных элементов. И, наконец, источник данных полей со списком обновляется, и выбор устанавливается на первоначально выбранный элемент. Мы потеряем «выбранный» элемент поля со списком, когда мы обновим его DataSource , и мы хотим, чтобы поле со списком сохраняло текущий выбранный элемент, поэтому нам нужно вернуть его исходное значение. Это событие ComboBox_SelectedIndexChanged может выглядеть примерно так…

Ниже небольшой пример приведенного выше кода в действии.

Я надеюсь, что это имеет смысл и помогает.

Привязать данные к комбинированным спискам с помощью DataSource , а затем повторно привязать их без заданного элемента.

На основании обсуждения в комментариях я даю вам полное решение.

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

enter image description here

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

Попробуйте отменить выбор текста после закрытия DropDown:

Трудная проблема для решения. Это похоже на событие Resize . Есть много решений, которые делают что-то похожее на это, но никто из тех, кого я видел, не работал у меня, пока я не попробовал это. (Это решение, которое не требует наследования от ComboBox ; наследование, вероятно, гораздо более прямое решение, но требует, чтобы вы всегда использовали свой унаследованный класс, а не фактический класс ComboBox .)

Установите длину выделения в ноль, чтобы избавиться от выделения, но когда? Другие примеры делают это в других местах, но проблема, по-видимому, вызвана специально Resize , поэтому после Resize она исправляется последовательно, по крайней мере для меня. (Может все еще видеть, что это мерцает, когда вы изменяете размер окна, но оно всегда заканчивается нормально.)

BeginInvoke гарантирует, что это произойдет достаточно после Resize для работы, а проверка для IsHandleCreated запрещает его вызывать до создания дескриптора, и в этом случае BeginInvoke выдаст исключение.

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

Я попытался создать версию, которая "сохранила" длину выделения, а не всегда устанавливала ее на ноль, но я не мог заставить ее правильно синхронизировать. Многие события Resize могут запускаться до того, как делегаты BeginInvoke начнут запускаться, поэтому сохраненное значение всегда будет перезаписано сломанным. Я попытался сохранить их все в Queue или Stack , но в обоих случаях мне не удалось отменить порядок (не совсем уверен, почему, поскольку это не имеет смысла).

Читайте также: