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