При работе с обычными формами в 1С:Предприятие 8, особенно на старых конфигурациях, часто возникает задача ограничить для пользователя выбор значений из перечисления. Стандартный подход с использованием свойства СписокВыбора может привести к неприятному побочному эффекту: если в реквизите уже записано какое-то значение, поле на форме при открытии может оказаться пустым. Давайте подробно разберем, почему так происходит и как этого избежать.
Проблема, с которой столкнулся автор, заключается в двух моментах:
СписокВыбора и обработчик НачалоВыбораИзСписка), поле ввода на форме становится пустым при открытии, хотя связанный с ним реквизит данных заполнен.Проанализируем ситуацию и найдем правильное решение.
Это ключевой момент, который нужно понять. Когда вы для элемента формы (поля ввода) устанавливаете режим выбора из списка и программно управляете этим списком через свойство СписокВыбора, платформа 1С при отрисовке формы выполняет простую проверку: "Присутствует ли текущее значение реквизита в предоставленном списке выбора?".
Если ответ "Да", платформа находит соответствующий элемент в списке и отображает его представление (например, "Активен", "Завершен").
Если ответ "Нет", платформа не может найти соответствие. Она не знает, какое представление показать для значения, которого нет в разрешенном списке. В результате, чтобы не вводить пользователя в заблуждение, она отображает поле как пустое. Хотя на уровне данных, в реквизите объекта, значение по-прежнему хранится.
Именно это и произошло в сообщении (2): список для выбора формируется, но в него не попадает уже сохраненное значение, из-за чего при открытии формы мы видим пустоту.
Самый надежный и правильный способ — это формировать список выбора при открытии формы, убедившись, что текущее значение реквизита в этот список обязательно включено. Разберем по шагам, как это сделать.
Создаем обработчик события формы ПриОткрытии(). Именно в этот момент нам нужно подготовить все элементы формы к отображению.
Формируем список разрешенных значений. Внутри обработчика создаем новый объект СписокЗначений и заполняем его теми значениями перечисления, которые должны быть доступны пользователю для выбора.
// Процедура выполняется в модуле формы
Процедура ПриОткрытии()
// Создаем пустой список значений
ОграниченныйСписок = Новый СписокЗначений;
// Добавляем в него только те значения, которые разрешены пользователю
ОграниченныйСписок.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);
ОграниченныйСписок.Добавить(Перечисления.СтатусыЗаказов.Выполнен);
ОграниченныйСписок.Добавить(Перечисления.СтатусыЗаказов.Отменен);
// ... остальной код ...
КонецПроцедуры
Добавляем текущее значение (критически важный шаг!). Перед тем как присвоить наш список элементу формы, нужно проверить, заполнено ли значение в реквизите объекта. Если оно заполнено и вдруг не попало в наш отфильтрованный список (например, это старый заказ со статусом "Архивный", который мы не разрешаем выбирать), его все равно нужно добавить в СписокВыбора. Иначе поле будет пустым!
// Продолжение кода в процедуре ПриОткрытии()
// Получаем текущее значение реквизита, к которому привязано поле
ТекущееЗначение = ЭтотОбъект.СтатусЗаказа; // Предположим, реквизит называется СтатусЗаказа
// Проверяем, что значение заполнено и его нет в нашем списке
Если ЗначениеЗаполнено(ТекущееЗначение) И ОграниченныйСписок.НайтиПоЗначению(ТекущееЗначение) = Неопределено Тогда
// Если его нет - добавляем! Это нужно для корректного отображения.
ОграниченныйСписок.Добавить(ТекущееЗначение, "!!! " + Строка(ТекущееЗначение)); // Можно добавить пометку для наглядности
КонецЕсли;
Важно: даже если вы добавите "запрещенное" значение для отображения, пользователь не сможет его выбрать, если вы будете переформировывать список в событии НачалоВыбора (см. Решение 2).
Присваиваем готовый список элементу формы. Последний шаг — присвоить наш подготовленный СписокЗначений свойству СписокВыбора нужного поля ввода.
// Завершение кода в процедуре ПриОткрытии()
// Находим нужный элемент на форме и устанавливаем ему список выбора
ЭлементыФормы.СтатусЗаказа.СписокВыбора = ОграниченныйСписок;
КонецПроцедуры
Этот подход гарантирует, что при открытии формы ранее сохраненное значение всегда будет отображаться корректно.
Часто бывает, что список доступных значений перечисления зависит от других данных на форме (например, статусы документа зависят от его суммы или контрагента). В этом случае логику формирования списка нужно размещать в обработчике события поля ввода НачалоВыбора.
Этот метод отлично сочетается с первым. В ПриОткрытии() мы обеспечиваем первоначальное отображение, а в НачалоВыбора — формируем актуальный список для пользователя в момент клика по кнопке выбора.
// Обработчик события "НачалоВыбора" для поля ввода "СтатусЗаказа"
Процедура СтатусЗаказаНачалоВыбора(Элемент, СтандартнаяОбработка)
// Запрещаем стандартное поведение платформы (открытие полного списка перечисления)
СтандартнаяОбработка = Ложь;
// Создаем и заполняем список заново, на основе текущих условий
СписокДляВыбора = Новый СписокЗначений;
// Пример динамического условия
Если ЭтотОбъект.СуммаДокумента > 100000 Тогда
// Для крупных заказов доступны особые статусы
СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.НаСогласовании);
СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Согласован);
Иначе
// Для обычных заказов
СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Новый);
СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);
КонецЕсли;
СписокДляВыбора.Добавить(Перечисления.СтатусыЗаказов.Отменен); // Этот статус доступен всегда
// Присваиваем обновленный список элементу формы
Элемент.СписокВыбора = СписокДляВыбора;
КонецПроцедуры
При таком подходе пользователь при каждом открытии списка выбора будет видеть только актуальные для текущего контекста значения.
Иногда, если логика слишком сложна, можно применить "обходной маневр", предложенный в сообщении (5). Суть его в том, чтобы разорвать прямую связь между полем на форме и реквизитом данных.
ВыбранныйСтатус с тем же типом "Перечисление").ВыбранныйСтатус.СписокВыбора, как описано в решениях выше. При открытии формы копируйте в него значение из основного реквизита: ВыбранныйСтатус = ЭтотОбъект.СтатусЗаказа.ПриИзменении.ЭтотОбъект.СтатусЗаказа = ВыбранныйСтатус.Плюсы этого метода: максимальная гибкость, вы полностью контролируете логику.
Минусы: больше кода, нужно вручную синхронизировать данные между реквизитом формы и реквизитом объекта, что может привести к ошибкам, если что-то упустить.
В большинстве случаев достаточно грамотно использовать первое и второе решение, которые являются штатными и более надежными механизмами платформы 1С.