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