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