Как передать и отобразить таблицу значений на управляемой форме в 1С 8.3

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

Передача сформированной в коде таблицы значений на форму и её последующее отображение — одна из стандартных задач при разработке в среде 1С:Предприятие 8.3. Однако при переходе с обычных форм на управляемые разработчики часто сталкиваются с ошибками типизации и клиент-серверного взаимодействия.

Проанализируем ключевые особенности клиент-серверной архитектуры платформы. Объект ТаблицаЗначений существует исключительно на стороне сервера. Его невозможно использовать на тонком или веб-клиенте, а также нельзя напрямую передать в структуру параметров клиентского метода ОткрытьФорму(), так как данный тип не поддерживает сериализацию. Кроме того, реквизит управляемой формы с типом «ТаблицаЗначений» в контексте исполняемого кода формы представляет собой специальный объект — ДанныеФормыКоллекция.

Рассмотрим подробнее типовые сценарии и выясним, как правильно передать данные и вывести их пользователю в зависимости от того, известна ли структура колонок заранее.

Способ 1. Передача через временное хранилище (рекомендуемый подход)

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

Разберем по шагам реализацию этого механизма:

  1. На сервере помещаем готовую таблицу значений во временное хранилище с привязкой к уникальному идентификатору формы-источника или генерируем новый УникальныйИдентификатор. Это гарантирует, что данные не будут очищены сборщиком мусора до момента их прочтения.
  2. Передаем полученный строковый адрес хранилища в параметрах метода ОткрытьФорму().
  3. В обработчике ПриСозданииНаСервере открываемой формы извлекаем таблицу значений и загружаем её в данные формы.

Посмотрим на пример кода вызова из формы-источника или общей команды:


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

    СтрокаТаблицы = ТаблицаДанных.Добавить();
    СтрокаТаблицы.Артикул = "A-001";
    СтрокаТаблицы.Количество = 15;

    // Обязательно связываем адрес с УникальнымИдентификатором формы
    Возврат ПоместитьВоВременноеХранилище(ТаблицаДанных, УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура ОткрытьФормуСТаблицей()
    АдресДанных = ПоместитьТаблицуВХранилище();

    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АдресХранилищаТаблицы", АдресДанных);

    ОткрытьФорму("Обработка.МояОбработка.Форма.ФормаОтображения", ПараметрыОткрытия);
КонецПроцедуры

Теперь рассмотрим код, который должен располагаться в модуле открываемой формы (где уже создан реквизит формы ТаблицаНаФорме с соответствующими колонками):


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("АдресХранилищаТаблицы") И ЗначениеЗаполнено(Параметры.АдресХранилищаТаблицы) Тогда
        ТаблицаИзХранилища = ПолучитьИзВременногоХранилища(Параметры.АдресХранилищаТаблицы);

        Если ТипЗнч(ТаблицаИзХранилища) = Тип("ТаблицаЗначений") Тогда
            // Загружаем данные в реквизит формы
            ЗначениеВРеквизитФормы(ТаблицаИзХранилища, "ТаблицаНаФорме");
            
            // Также доступен альтернативный метод:
            // ЭтотОбъект.ТаблицаНаФорме.Загрузить(ТаблицаИзХранилища);

            // Очищаем временное хранилище после чтения для экономии памяти
            УдалитьИзВременногоХранилища(Параметры.АдресХранилищаТаблицы);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Способ 2. Загрузка в реквизит формы с известным составом колонок

Если таблица значений формируется непосредственно в контексте открытой формы (например, по нажатию кнопки), передача через временное хранилище не требуется. Достаточно серверного вызова, где таблица значений преобразуется в объект ДанныеФормыКоллекция.

В платформе 1С для этого предусмотрено два способа:

  1. Метод формы ЗначениеВРеквизитФормы(ТаблицаИсточник, "ИмяРеквизита") — выполняет полное сопоставление типов и переносит структуру в реквизит формы.
  2. Метод коллекции ЭлементыДанных.Загрузить(ТаблицаИсточник) — заполняет существующие строки реквизита формы по совпадающим именам колонок.

Посмотрим на пример работы в модуле открытой формы:


&НаСервере
Процедура ЗаполнитьРеквизитНаСервере()
    Таблица = Новый ТаблицаЗначений;
    Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(10)));
    Таблица.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100)));

    НоваяСтрока = Таблица.Добавить();
    НоваяСтрока.Код = "00001";
    НоваяСтрока.Наименование = "Товар 1";

    // Способ переноса данных:
    ЗначениеВРеквизитФормы(Таблица, "ТаблицаНаФорме");
КонецПроцедуры

&НаКлиенте
Процедура ЗаполнитьТаблицу(Команда)
    ЗаполнитьРеквизитНаСервере();
КонецПроцедуры

Способ 3. Динамическое создание колонок и элементов интерфейса

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

Важно: метод ИзменитьРеквизиты() приводит к переинициализации контекста формы на сервере, что повышает нагрузку. Если процедура выполняется повторно в процессе работы, необходимо обязательно удалить ранее созданные динамические реквизиты, передав массив их имен вторым параметром метода ИзменитьРеквизиты(), чтобы избежать ошибки дублирования имен.

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


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

    // Применяем изменения структуры формы
    ИзменитьРеквизиты(НовыеРеквизиты);

    // 2. Создаем визуальные элементы формы для каждой колонки
    РодительТаблица = Элементы[ИмяЭлементаТаблицы];

    Для Каждого Колонка Из ТабВКоде.Колонки Цикл
        ИмяЭлементаКолонки = ИмяРеквизитаТаблицы + "_" + Колонка.Имя;

        НовыйЭлемент = Элементы.Добавить(ИмяЭлементаКолонки, Тип("ПолеФормы"), РодительТаблица);
        НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
        НовыйЭлемент.ПутьКДанным = ИмяРеквизитаТаблицы + "." + Колонка.Имя;
        НовыйЭлемент.Заголовок = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
    КонецЦикла;

    // 3. Заполняем реквизит данными из таблицы
    ЗначениеВРеквизитФормы(ТабВКоде, ИмяРеквизитаТаблицы);
КонецПроцедуры

&НаСервере
Процедура СоздатьТаблицуНаФормеНаСервере()
    ТабВКоде = Новый ТаблицаЗначений;
    ТабВКоде.Колонки.Добавить("Колонка1", Новый ОписаниеТипов("Строка")); 
    ТабВКоде.Колонки.Добавить("Колонка2", Новый ОписаниеТипов("Число"));
    ТабВКоде.Колонки.Добавить("Колонка3", Новый ОписаниеТипов("Дата"));

    СтрВКоде = ТабВКоде.Добавить();
    СтрВКоде.Колонка1 = "Тестовая строка";
    СтрВКоде.Колонка2 = 42;
    СтрВКоде.Колонка3 = ТекущаяДата();

    ВывестиТаблицуЗначенияВКодеВТаблицуНаФорме(ТабВКоде, "ТабРеквизит", "ТабНаФорме");
КонецПроцедуры

&НаКлиенте
Процедура СоздатьТаблицуНаФорме(Команда)
    СоздатьТаблицуНаФормеНаСервере();
КонецПроцедуры

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

← На главную