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