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