При разработке внешних отчетов и обработок в среде «1С:Предприятие» (особенно на обычных формах, таких как в конфигурации «Зарплата и Управление Персоналом 2.5») часто возникает задача предоставить пользователю возможность выбора элементов справочника в список значений с предварительной фильтрацией. Типичный пример — выбор значений подчиненного справочника (например, ЗначенияСвойствОбъектов) с отбором по его владельцу (конкретному свойству из Плана видов характеристик СвойстваОбъектов).
В этой статье мы подробно разберем, почему стандартные подходы могут не работать (например, когда выбранные элементы не возвращаются в поле ввода), проанализируем ошибки разработчиков и рассмотрим несколько эффективных способов решения этой задачи как программным путем, так и с помощью настроек метаданных.
Рассмотрим ситуацию, с которой столкнулся автор темы. В обработчике события СписокБазНачалоВыбора был написан следующий код:
Процедура СписокБазНачалоВыбора(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ПараметрыФормы = Новый Структура("РежимВыбора, Отбор", Истина, Новый Структура("Владелец", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоКоду("0006")));
ОткрытьФормуМодально("Справочник.ЗначенияСвойствОбъектов.ФормаВыбора", ПараметрыФормы, ЭтаФорма);
КонецПроцедуры
На первый взгляд код выглядит логичным, однако при интерактивном двойном щелчке по элементу в открывшейся форме выбора данные не попадали обратно в поле ввода на форме отчета. Давайте выясним причину этого поведения.
В платформе «1С:Предприятие» при работе с обычными формами метод ОткрытьФормуМодально, вызванный с передачей структуры параметров, не всегда корректно связывает вызывающий элемент управления с открываемой формой. Для того чтобы форма выбора знала, куда именно нужно вернуть результат, ей необходимо передать контекст — владельца формы (в данном случае это сам элемент управления поля ввода Элемент, а не объект ЭтаФорма).
Кроме того, если мы переопределяем стандартную обработку (СтандартнаяОбработка = Ложь), платформа полностью снимает с себя обязательства по автоматическому заполнению поля. Мы должны либо явно получить возвращаемое значение и присвоить его, либо правильно связать форму выбора с элементом управления.
Ниже мы подробно разберем четыре практических способа реализации этой задачи.
Для того чтобы выбранное значение автоматически возвращалось в поле ввода списка значений, нам необходимо использовать метод ПолучитьФормуВыбора. В качестве владельца формы мы должны передать не саму форму отчета (ЭтаФорма), а именно элемент управления, в котором осуществляется выбор. В этом случае платформа сама обработает выбор и поместит элемент в список.
Разберем этот вариант по шагам и напишем правильный обработчик события:
Процедура СписокБазНачалоВыбора(Элемент, СтандартнаяОбработка)
// Отменяем стандартное открытие формы без отборов
СтандартнаяОбработка = Ложь;
// Находим нужное свойство-владелец (ПВХ)
НужныйВладелец = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоКоду("0006");
Если Не ЗначениеЗаполнено(НужныйВладелец) Тогда
Предупреждение("Не найден владелец свойств с кодом '0006'!");
Возврат;
КонецЕсли;
// Получаем форму выбора справочника.
// Второй параметр - Элемент - указывает, куда вернуть выбранное значение.
ФормаВыбора = Справочники.ЗначенияСвойствОбъектов.ПолучитьФормуВыбора("ФормаВыбора", Элемент);
// Настраиваем отбор по владельцу в открываемой форме
ФормаВыбора.Отбор.Владелец.Использование = Истина;
ФормаВыбора.Отбор.Владелец.Значение = НужныйВладелец;
ФормаВыбора.Отбор.Владелец.ВидСравнения = ВидСравнения.Равно;
// Блокируем изменение отбора пользователем (при необходимости)
ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Владелец.Доступность = Ложь;
// Открываем форму модально
ФормаВыбора.ОткрытьМодально();
КонецПроцедуры
Важный нюанс: передача параметра Элемент в метод ПолучитьФормуВыбора связывает форму выбора с полем ввода на нашей форме. При двойном клике в форме выбора значение автоматически добавится в список значений без написания дополнительного кода возврата.
Если перед пользователем стоит задача выбрать не один элемент за раз, а сразу несколько (что является стандартным сценарием при работе со списками значений), обычный режим выбора может оказаться неудобным, так как форму придется открывать повторно для каждого элемента. В этом случае мы рекомендуем организовать полноценный режим подбора.
Для этого мы разделим процесс на два этапа: вызов формы подбора и обработка результатов выбора.
Шаг 1. Открываем форму в режиме подбора:
Процедура СписокБазНачалоВыбора(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
НужныйВладелец = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоКоду("0006");
// Создаем структуру параметров для установки отбора
ПараметрыОтбора = Новый Структура("Владелец", НужныйВладелец);
// Открываем форму в режиме подбора.
// Третьим параметром передаем Элемент, чтобы связать событие выбора с нашей формой.
ОткрытьФорму("Справочник.ЗначенияСвойствОбъектов.ФормаВыбора", ПараметрыОтбора, Элемент);
КонецПроцедуры
Шаг 2. Обрабатываем выбор в событии ОбработкаВыбора поля ввода. Нам необходимо подписать наше поле ввода (или саму форму) на событие ОбработкаВыбора и добавить туда следующий код:
Процедура СписокБазОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Отменяем стандартное поведение платформы
СтандартнаяОбработка = Ложь;
// Проверяем, что значение выбрано и его еще нет в нашем списке
Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
Если ЭлементыФормы.СписокБаз.Значение.НайтиПоЗначению(ВыбранноеЗначение) = Неопределено Тогда
ЭлементыФормы.СписокБаз.Value.Добавить(ВыбранноеЗначение);
Сообщить("Добавлено значение: " + ВыбранноеЗначение);
Иначе
Предупреждение("Данное значение уже присутствует в списке!");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ является наиболее эргономичным для конечного пользователя, так как форма выбора не закрывается после каждого клика, позволяя быстро набрать необходимый список элементов.
Если мы работаем в среде, где конфигурация открыта для редактирования, или создаем собственный внешний отчет с нуля, мы можем избежать написания кода в модуле формы вообще. Для этого используются встроенные механизмы связей параметров выбора.
Рассмотрим, как настроить это визуально в конфигураторе:
СписокЗначений.Отбор.Владелец(ПараметрВладелец).Этот способ является наиболее предпочтительным с точки зрения стандартов разработки фирмы «1С», так как он использует декларативный подход и оптимально работает на уровне платформы.
В сообщении №4 автор упоминает критически важное ограничение: «Конфа на замках...». Это означает, что вносить изменения в типовую конфигурацию «Зарплата и Управление Персоналом» нельзя, а все доработки должны быть выполнены строго в рамках одного внешнего файла отчета (.erf).
Если типовая форма выбора справочника ЗначенияСвойствОбъектов не обладает нужной нам гибкостью (например, в ней скрыта колонка «Владелец» или жестко переопределяются отборы при открытии), самым надежным и стабильным решением будет создание собственной формы выбора непосредственно внутри внешнего отчета.
Давайте разберем, как это реализовать:
ФормаВыбораЗначенийСвойств.СправочникСписок.ЗначенияСвойствОбъектов.ПриОткрытии напишем жесткий отбор по входящему параметру владельца:
Процедура ПриОткрытии()
// Устанавливаем отбор по переданному владельцу свойства
Если ЗначениеЗаполнено(ПараметрВладелец) Тогда
СправочникСписок.Отбор.Владелец.Установить(ПараметрВладелец);
КонецЕсли;
КонецПроцедуры
Работая с подчиненными справочниками и планами видов характеристик, всегда помните о следующих правилах:
ВидСравнения.Равно). Использование других видов сравнения (например, «В списке») для поля Владелец платформой может не поддерживаться на уровне СУБД.Использование = Истина, иначе платформа проигнорирует переданное значение отбора.Мы подробно разобрали все возможные варианты решения проблемы выбора элементов справочника с отбором. Выбирайте наиболее подходящий способ в зависимости от ваших задач и ограничений доступа к изменению конфигурации!