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