Можно ли создать динамический список на основе программной таблицы значений в 1С?

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

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

Почему возникает ошибка при передаче ТаблицыЗначений в динамический список

Попытка использовать следующий запрос в динамическом списке:


ВЫБРАТЬ
    ТЗ.К1,
    ТЗ.К2
ПОМЕСТИТЬ Таблица
ИЗ
    &ТЗ КАК ТЗ
;
ВЫБРАТЬ
    Таблица.К1,
    Таблица.К2
ИЗ
    Таблица КАК Таблица

приводит к ошибке исполнения:

«Ошибка получения информации набора данных... Неверные параметры "ТЗ"».

Выясним причину такого поведения. Механизм динамического списка предназначен для порционного считывания данных напрямую из СУБД. Платформа 1С динамически модифицирует исходный текст запроса, добавляя условия сортировки, пользовательские отборы, группировки и ограничения по количеству строк (постраничную выборку). Динамический список работает исключительно с постоянными таблицами базы данных (справочники, документы, регистры). Передать во внутренний контекст динамического списка объект из оперативной памяти сервера (таблицу значений, массив или дерево значений) платформа 1С не позволяет.

Вариант 1. Программное создание реквизитов и элементов формы

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

Рассмотрим по шагам программное создание таблицы формы на основе таблицы значений:

  1. Создаем описание типа для реквизита таблицы формы и добавляем сам реквизит типа ТаблицаЗначений.
  2. Считываем колонки из исходной таблицы значений и формируем массив новых реквизитов-колонок с соответствующими типами данных.
  3. Применяем изменения структуры формы с помощью вызова ИзменитьРеквизиты.
  4. Создаем визуальный элемент интерфейса ТаблицаФормы и привязываем его к созданному реквизиту.
  5. В цикле добавляем поля ввода (колонки) в созданную таблицу формы.
  6. Загружаем данные из объекта в созданный реквизит формы с помощью метода ЗначениеВРеквизитФормы.

Посмотрим на пример реализации серверной процедуры:


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

Вариант 2. Использование служебного регистра для больших объемов данных

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

Разберем архитектуру такого решения:

  1. В конфигурации создается непериодический регистр сведений (например, ВременныеДанныеФорм).
  2. В состав измерений регистра включаются ИдентификаторСеанса (тип УникальныйИдентификатор) и НомерСтрокиДанных (тип Число), а в ресурсы — необходимые поля под хранение значений.
  3. При открытии формы сформированная таблица значений программно записывается в регистр сведений с указанием текущего уникального идентификатора формы или сеанса.
  4. На форме настраивается стандартный ДинамическийСписок, источником которого является данный регистр сведений с установленным фиксированным отбором по измерению ИдентификаторСеанса.
  5. При закрытии формы или через регламентное задание выполняется очистка записей регистра по завершенным сеансам.

Вариант 3. Использование отчета на СКД и табличного документа

Если данные предназначены исключительно для просмотра, агрегации или выгрузки без интерактивного редактирования каждой ячейки:

  1. Создаем схему компоновки данных (СКД), где в качестве источника настраивается «Набор данных — объект».
  2. В модуле передаем таблицу значений через коллекцию ВнешниеНаборыДанных.
  3. Выводим результат компоновки в элемент формы типа ПолеТабличногоДокумента.

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

Вариант 4. Постраничный вывод (пагинация)

Если требуется отображать таблицу значений с возможностью выбора строк, но объем данных велик, реализуем механизм пагинации:

  1. Таблица значений сохраняется во временном хранилище на сервере.
  2. В реквизит формы загружается только ограниченная порция строк текущей страницы (например, по 50–100 записей).
  3. На форму добавляются кнопки переключения («Вперед», «Назад», «Номер страницы»), по нажатию которых реквизит формы очищается и заполняется следующей порцией строк из сохраненного массива.
← На главную