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