При разработке интерфейсов на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с задачей ограничения ввода данных в поле конкретным набором значений. Самый простой и логичный способ — установить свойство элемента формы РежимВыбораИзСписка в значение Истина. Однако здесь кроется ловушка: после записи объекта и повторного открытия формы поле часто оказывается пустым, хотя в базе данных значение сохранено. Проанализируем ситуацию, выясним причины такого поведения платформы и рассмотрим пошаговые инструкции по исправлению этой ошибки.
Рассмотрим, как работает свойство РежимВыбораИзСписка (ListChoiceMode). Когда этот флаг установлен, поле ввода начинает работать не как стандартное поле выбора из справочника, а как поле со строгим соответствием списку. Платформа 1С в этом режиме выполняет следующие действия:
СписокВыбора (ChoiceList), связанной с этим элементом формы.Таким образом, если вы заполняете список выбора только в событии НачалоВыбора, то при открытии формы список пуст, и платформа "скрывает" существующее значение. Выясним, как правильно инициализировать данные.
Проанализируем самый надежный метод решения. Чтобы данные отобразились сразу при открытии формы, коллекция СписокВыбора должна быть заполнена до того, как форма будет отрисована на экране пользователя. Оптимальное место для этого — серверный обработчик ПриСозданииНаСервере.
Посмотрим на пример кода, который формирует список выбора из предопределенных элементов или по определенному фильтру:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Очищаем старый список, если он был
Элементы.Помещения.СписокВыбора.Очистить();
// Выбираем только нужные данные, например, активные помещения
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Помещения.Ссылка КАК Ссылка,
| Помещения.Наименование КАК Наименование
|ИЗ
| Справочник.Помещения КАК Помещения
|ГДЕ
| Помещения.ВидПомещения = &ВидПомещения";
Запрос.УстановитьПараметр("ВидПомещения", Перечисления.ВидыПомещений.Жилое);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Элементы.Помещения.СписокВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
КонецЦикла;
КонецПроцедуры
Важный нюанс: тип добавляемого значения в СписокВыбора должен строго совпадать с типом реквизита. Если реквизит имеет тип СправочникСсылка, в список нужно добавлять именно ссылку, а не строку с наименованием.
Бывают ситуации, когда список выбора меняется динамически или фильтруется. В этом случае может возникнуть проблема: в поле уже записано старое значение, которое больше не попадает в новый фильтр. Чтобы пользователь видел, что именно выбрано в объекте (даже если это значение уже нельзя выбрать заново), проанализируем следующий алгоритм:
Рассмотрим пример реализации такой логики:
&НаСервере
Процедура АктуализироватьСписокВыбора()
Список = Элементы.ПолеПомещение.СписокВыбора;
ТекущееЗначение = Объект.Помещение;
// Если значение в объекте есть, а в списке его нет - добавляем
Если ЗначениеЗаполнено(ТекущееЗначение) Тогда
НайденныйЭлемент = Список.НайтиПоЗначению(ТекущееЗначение);
Если НайденныйЭлемент = Неопределено Тогда
Список.Добавить(ТекущееЗначение, Строка(ТекущееЗначение) + " (архив)");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если список выбора заполняется программно в процессе работы пользователя (например, после изменения другого поля), платформа иногда "подтормаживает" с обновлением визуального состояния. Для этого в арсенале разработчика есть специальные методы. Разберем их применение.
Метод ОповеститьОбИзменении полезен, когда нужно сказать платформе, что данные реквизита обновились и их нужно перечитать из списка выбора. Однако более современным и точным способом является метод формы ОбновитьОтображениеДанных().
Посмотрим на пример использования при динамическом перестроении списка:
&НаКлиенте
Процедура ПослеИзмененияТипаПомещения(Элемент)
// Вызываем серверную процедуру переполнения списка выбора
ПерезаполнитьСписокНаСервере();
// Принудительно обновляем форму, чтобы значение сопоставилось с новым списком
ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры
В некоторых версиях платформы (особенно в режиме совместимости или в веб-клиенте) наблюдается странное поведение: список заполнен, значение в объекте есть, но поле все равно пустое до тех пор, пока на нем не сфокусируешься. В таких случаях программисты используют проверенный временем прием — фиктивное присваивание значения самому себе.
Выясним, как это выглядит в коде:
&НаСервере
Процедура ПриОткрытииНаСервере()
// Сначала заполняем список...
ЗаполнитьСписокПомещений();
// Затем "дергаем" реквизит, чтобы вызвать триггер обновления интерфейса
Если ЗначениеЗаполнено(Объект.Помещение) Тогда
Объект.Помещение = Объект.Помещение;
КонецЕсли;
КонецПроцедуры
Этот метод заставляет платформу заново выполнить поиск соответствия между Объект.Помещение и записями в Элементы.Помещение.СписокВыбора.
Разберем еще один нюанс, упомянутый в обсуждении. При включенном свойстве БыстрыйВыбор (QuickChoice) и одновременном использовании РежимВыбораИзСписка часто возникает системная ошибка "Неправильное условие отбора", особенно если на поле наложены параметры выбора по предопределенным данным.
Проанализируем ситуацию: Быстрый выбор пытается работать как индексированный поиск по справочнику, в то время как Режим выбора из списка замыкает поиск внутри локальной коллекции. Эти механизмы конфликтуют. Если вам нужно программно ограничивать список, выключите БыстрыйВыбор и ИспользоватьСписокВыбораПриВводеТекста в палитре свойств, оставив только РежимВыбораИзСписка. Все ограничения реализуйте только через заполнение коллекции СписокВыбора.
Подводя итог, можно составить краткий чек-лист для корректной работы РежимВыбораИзСписка:
СписокВыбора в процедуре ПриСозданииНаСервере или ПриЧтенииНаСервере.Добавить) в точности совпадает с типом данных реквизита формы.ЭтаФорма.ОбновитьОтображениеДанных().Соблюдение этих правил обеспечит стабильное отображение данных и комфортную работу пользователей с вашими формами.