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