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