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