Как правильно заполнить список значений на сервере 1С и избежать ошибки отображения типов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработка на платформе «1С:Предприятие 8» в режиме управляемого приложения требует от программиста четкого понимания принципов клиент-серверного взаимодействия. Одна из классических задач, с которой сталкиваются как начинающие, так и опытные специалисты, — это необходимость заполнить список значений (реквизит формы) при ее открытии, а затем вернуть выбранный элемент на клиент. Казалось бы, простая задача часто оборачивается непонятными на первый взгляд ошибками сериализации данных XDTO.

В рамках этой статьи мы подробно разберем, почему возникает популярная ошибка «Ошибка отображения типов: Отсутствует отображение для типа 'ЭлементСпискаЗначений'», проанализируем внутренние механизмы платформы 1С и изучим три надежных способа правильного заполнения реквизита формы на сервере, а также рассмотрим корректный возврат выбранного значения.

---

Выясняем причину: почему возникает ошибка отображения типов?

Проанализируем ситуацию, описанную разработчиком. При создании управляемой формы на сервере вызывается экспортный метод, возвращающий список доступных функций в виде стандартного объекта СписокЗначений. Пытаясь заполнить реквизит формы СписокАвтоподстановок (который на клиенте и сервере представлен коллекцией ДанныеФормыСписокЗначений), разработчик использует следующий цикл:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Автоподстановки = ШаблоныБизнесПроцессовПереопределяемый.ПолучитьСписокДоступныхФункций(Неопределено);
    Для Каждого Стр Из Автоподстановки Цикл
        СписокАвтоподстановок.Добавить(Стр); // Здесь кроется критическая ошибка!
    КонецЦикла;
КонецПроцедуры

Внешне код выглядит вполне логично, однако при попытке открыть форму платформа аварийно завершает работу и выдает ошибку преобразования данных XDTO. Давайте разберем по шагам, что происходит в этот момент внутри платформы 1С:

  1. Переменная Автоподстановки содержит объект типа СписокЗначений.
  2. При обходе этой коллекции с помощью цикла Для Каждого, итератор Стр на каждом шаге получает тип ЭлементСпискаЗначений. Этот объект содержит три основных свойства: Значение, Представление, Пометка и Картинка.
  3. Выполняя команду СписокАвтоподстановок.Добавить(Стр), разработчик передает в метод весь объект ЭлементСпискаЗначений целиком. Платформа послушно записывает этот сложный системный объект в поле Значение нового элемента реквизита формы.
  4. После завершения процедуры ПриСозданииНаСервере управление возвращается на клиент. Платформа инициирует процесс контекстной передачи данных формы. Для этого ей необходимо сериализовать (сконвертировать в XML-подобный формат XDTO) все данные, хранящиеся в реквизитах.
  5. Поскольку тип ЭлементСпискаЗначений является исключительно внутренним серверным типом и не предназначен для передачи по каналам связи между клиентом и сервером в качестве самостоятельного значения, сериализатор XDTO выдает ошибку: «Отсутствует отображение для типа 'ЭлементСпискаЗначений'».

Таким образом, мы выяснили причину проблемы: нельзя помещать системные элементы одного списка значений внутрь другого списка значений. Хранить в элементах списка можно только простые прикладные типы данных (ссылки, строки, числа, булево, даты) или массивы/структуры, поддерживающие сериализацию.

---

Решение №1: Ручной обход коллекции с извлечением свойств

Самый очевидный способ исправить ситуацию — это правильно передавать параметры в метод Добавить() реквизита формы. Мы должны явно указать, что из итерируемого элемента нужно брать именно прикладное значение и, при необходимости, его текстовое представление.

Рассмотрим пример правильного серверного кода:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Получаем исходный список значений из общего модуля
    Автоподстановки = ШаблоныБизнесПроцессовПереопределяемый.ПолучитьСписокДоступныхФункций(Неопределено);
    
    // Заполняем реквизит формы, обращаясь к свойствам элементов напрямую
    Для Каждого ЭлементСписка Из Автоподстановки Цикл
        СписокАвтоподстановок.Добавить(ЭлементСписка.Значение, ЭлементСписка.Представление);
    КонецЦикла;
КонецПроцедуры

В данном случае в реквизит формы записываются только «чистые» прикладные данные (например, ссылки на справочники или строки) и их строковые представления, которые отлично поддаются сериализации. Платформа без проблем передаст эти данные на клиентскую сторону, и форма откроется корректно.

---

Решение №2: Высокопроизводительный метод через выгрузку и загрузку массива

Использование циклов Для Каждого в языке 1С — это классический подход, но он не всегда является самым производительным, особенно когда речь идет о сотнях или тысячах элементов. Платформа 1С предоставляет более быстрые встроенные методы для работы с коллекциями значений.

Мы можем воспользоваться связкой методов ВыгрузитьЗначения() у исходного списка значений и ЗагрузитьЗначения() у целевого реквизита формы. Метод ВыгрузитьЗначения() возвращает обычный одномерный массив, содержащий только чистые значения элементов списка (без их системных оболочек-элементов). Метод ЗагрузитьЗначения() принимает этот массив, предварительно очищая целевой список.

Посмотрим на пример реализации этого метода:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Получаем исходную коллекцию
    Автоподстановки = ШаблоныБизнесПроцессовПереопределяемый.ПолучитьСписокДоступныхФункций(Неопределено);
    
    // Быстро заполняем реквизит формы через массив значений в одну строку
    СписокАвтоподстановок.ЗагрузитьЗначения(Автоподстановки.ВыгрузитьЗначения());
КонецПроцедуры

Важное примечание: Этот способ идеален с точки зрения скорости работы системы. Однако стоит учитывать один нюанс: при выгрузке значений в массив теряются индивидуальные представления элементов (свойство Представление). Если вам критически важно сохранить особые текстовые представления элементов, настроенные в исходном списке значений, то лучше воспользоваться первым решением или третьим.

---

Решение №3: Использование функций преобразования данных формы

Иногда разработчики советуют применять встроенные функции платформы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы. Для простых операций наполнения списка они могут показаться избыточными, но знание этого механизма необходимо при реализации сложной логики (например, если требуется передать список значений в функции общих модулей, работающих исключительно с чистыми объектами типа СписокЗначений, а не с типами управляемых форм).

Разберем по шагам, как правильно выполнить данную операцию:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // 1. Конвертируем реквизит управляемой формы в реальный прикладной СписокЗначений
    ЧистыйСписок = РеквизитФормыВЗначение("СписокАвтоподстановок", Тип("СписокЗначений"));
    
    // 2. Получаем исходные данные
    Автоподстановки = ШаблоныБизнесПроцессовПереопределяемый.ПолучитьСписокДоступныхФункций(Неопределено);
    
    // 3. Заполняем прикладной объект
    Для Каждого Элемент Из Автоподстановки Цикл
        ЧистыйСписок.Добавить(Элемент.Значение, Элемент.Представление);
    КонецЦикла;
    
    // 4. Записываем измененный объект обратно в структуру данных формы
    ЗначениеВРеквизитФормы(ЧистыйСписок, "СписокАвтоподстановок");
КонецПроцедуры

Этот метод гарантирует полную совместимость типов на уровне прикладных объектов и позволяет использовать любые стандартные методы сортировки, сравнения и поиска, доступные только для чистого класса СписокЗначений.

---

Исправляем работу на клиенте: корректный возврат выбранного значения

После того как список значений успешно заполнился на сервере и отобразился на клиенте, пользователю необходимо выбрать строку и закрыть форму с передачей результата. В коде автора содержалась еще одна архитектурная ошибка, которая привела бы к падению платформы при закрытии формы:


&НаКлиенте
Процедура Выбрать(Команда)
    ВыбрАвтоподстановка = Элементы.СписокАвтоподстановок.ТекущиеДанные;
    Закрыть(ВыбрАвтоподстановка); // Ошибка! Передается элемент коллекции формы
КонецПроцедуры

Проанализируем ситуацию: свойство элемента формы ТекущиеДанные возвращает объект типа ДанныеФормыЭлементКоллекции. При передаче этого объекта в метод Закрыть() система попытается вернуть его в вызывающую форму через клиент-серверную границу, что опять приведет к ошибке сериализации.

Чтобы избежать этого, необходимо всегда возвращать конкретное сохраненное значение (например, ссылку или строку), а не контейнер элемента коллекции формы. Исправим код процедуры:


&НаКлиенте
Процедура Выбрать(Команда)
    // Получаем текущие данные строки списка на форме
    ТекущаяСтрока = Элементы.СписокАвтоподстановок.ТекущиеДанные;
    
    Если ТекущаяСтрока <> Неопределено Тогда
        // Возвращаем именно конкретное Значение, хранящееся внутри элемента коллекции
        Закрыть(ТекущаяСтрока.Значение);
    КонецЕсли;
КонецПроцедуры

---

Резюме и рекомендации

При работе с коллекциями данных на управляемых формах 1С всегда помните о следующих правилах:

Применяя эти несложные архитектурные паттерны разработки, вы навсегда избавите свои решения от неожиданных ошибок сериализации и обеспечите высокую скорость работы интерфейса вашей конфигурации.

← На главную