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