Как программно получить количество колонок и добавить новые колонки в Таблицу Значений на Управляемой Форме 1С?

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

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

В этой статье мы подробно разберем, почему привычный код вроде ТрудозатратыСотрудника.Колонки.Количество() вызывает ошибку в управляемых формах, выясним фундаментальные различия между объектами отображения данных и самими данными, а также рассмотрим практические и производительные способы получения структуры колонок и их программного добавления.

Выясняем причину: почему не работает привычный метод?

Давайте проанализируем ситуацию. В обычных формах табличное поле на форме напрямую связывалось с объектом ТаблицаЗначений. Мы могли легко написать ЭлементыФормы.ТабличноеПоле1.Колонки.Количество() и получить точный результат. В управляемом приложении архитектура взаимодействия клиента и сервера была полностью пересмотрена в целях оптимизации трафика.

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

  1. Реквизит формы (Данные): Имеет тип ДанныеФормыКоллекция. Его основная задача — хранить данные в максимально «легковесном» формате для передачи между клиентом и сервером. К нему обращаются напрямую по имени, например, ТрудозатратыСотрудника.
  2. Элемент формы (Визуальное отображение): Имеет тип ТаблицаФормы. Его задача — отображать данные пользователю на экране. К нему обращаются через коллекцию элементов: Элементы.ТрудозатратыСотрудника.

Тип ДанныеФормыКоллекция оптимизирован для работы на клиенте. Он представляет собой, упрощенно говоря, массив структур. У этого типа в управляемом интерфейсе принципиально отсутствует свойство Колонки. Именно поэтому попытка вызвать обращение к колонкам напрямую через реквизит формы приводит к ошибке выполнения.

Решение 1. Получение количества колонок на Сервере без «тяжелых» преобразований

Если перед нами стоит задача узнать количество колонок или их имена на стороне сервера, у нас есть несколько путей. Рассмотрим их подробнее.

Самый простой, но не всегда оптимальный способ — это преобразование реквизита формы в полноценную прикладную таблицу значений с помощью встроенного метода формы. Посмотрим на пример кода:


&НаСервере
Процедура ПолучитьКолонкиЧерезПреобразование()
    // Преобразуем коллекцию данных формы в реальную Таблицу Значений
    ТЗ = РеквизитФормыВЗначение("ТрудозатратыСотрудника");
    КоличествоКолонок = ТЗ.Колонки.Количество();
    Сообщить("Количество колонок в таблице: " + КоличествоКолонок);
КонецПроцедуры

Важное примечание: Метод РеквизитФормыВЗначение является достаточно ресурсоемким, так как он заново создает в памяти объект прикладного типа и копирует туда все данные. Если ваша таблица содержит тысячи строк, такое преобразование может вызвать заметную задержку.

Для оптимизации работы мы можем использовать другие, более легковесные методы типа ДанныеФормыКоллекция:

Решение 2. Как получить информацию о колонках на Клиенте

На клиенте (в директиве &НаКлиенте) ситуация усложняется: объект ТаблицаЗначений там недоступен в принципе, а у объекта ДанныеФормыКоллекция нет методов Выгрузить() или ВыгрузитьКолонки(). Как же быть?

Мы можем пойти по пути анализа визуальных элементов формы. Обратимся к свойству отображения нашей таблицы:


&НаКлиенте
Процедура ОпределитьКоличествоКолонокНаКлиенте()
    КоличествоВизуальныхКолонок = Элементы.ТрудозатратыСотрудника.ПодчиненныеЭлементы.Количество();
    ПоказатьПредупреждение(, "Элементов в таблице на форме: " + КоличествоВизуальныхКолонок);
КонецПроцедуры

Внимание! У этого способа есть критические ограничения:

  1. Коллекция ПодчиненныеЭлементы содержит не физические колонки данных, а элементы управления на форме. Если вы сгруппировали несколько колонок в визуальную группу (тип ГруппаКолонок), платформа посчитает эту группу как один элемент.
  2. Если у вас на форме есть невидимые колонки (свойство Видимость установлено в Ложь), они все равно будут присутствовать в коллекции подчиненных элементов, но если колонки исключены из состава видимости через настройки прав пользователей, поведение может отличаться.

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


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

Решение 3. Программное добавление колонок на управляемую форму

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

Разберем по шагам правильный алгоритм программного добавления колонок:

  1. Создание реквизита (данных): Сначала мы должны использовать системный метод формы ИзменитьРеквизиты(), чтобы добавить новое поле данных в структуру нашего реквизита ТрудозатратыСотрудника.
  2. Создание элемента формы (визуализация): После того как реквизит успешно создан, мы добавляем на форму элемент типа ПолеФормы и связываем его путь к данным с новым реквизитом.

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


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

Проанализируем важный аспект производительности при динамическом изменении формы. Метод ИзменитьРеквизиты() заставляет платформу полностью перекомпилировать контекст формы. Если вам нужно добавить сразу 10 колонок, ни в коем случае не вызывайте этот метод в цикле.

Правильный подход заключается в накоплении всех добавляемых и удаляемых реквизитов в массивы и вызове метода ИзменитьРеквизиты() ровно один раз в конце процедуры. Это убережет ваше приложение от серьезных зависаний интерфейса.

Резюме и лучшие практики

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

← На главную