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

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

При разработке на платформе «1С:Предприятие 8.3» программисты часто сталкиваются с задачей программного перебора колонок дерева значений. На первый взгляд задача кажется тривиальной, однако в управляемом приложении возникает серьезная преграда: различие между типами данных на стороне клиента и сервера. Разберем детально, почему обычный обход в цикле может «не прокатывать», и какими способами можно гарантированно получить имена всех колонок.

Понимание разницы между объектами данных

Прежде чем переходить к коду, проанализируем ситуацию. В 1С существует три принципиально разных сущности, которые мы привыкли называть «деревом»:

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

Решение 1: Получение колонок на сервере через конвертацию

Если нам нужно получить состав колонок в серверном контексте, самый простой и надежный способ — преобразовать ДанныеФормыДерево в полноценное ДеревоЗначений. Рассмотрим пример кода, который часто используется в таких случаях:


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

Важный нюанс: Метод РеквизитФормыВЗначение является довольно «тяжелым», так как он полностью копирует все данные из формы в новый объект в памяти. Если ваше дерево содержит тысячи строк, это может привести к заметным задержкам. В таких случаях лучше использовать метод Выгрузить(), который работает быстрее:


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

Решение 2: Использование метода ПолучитьРеквизиты

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


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

Решение 3: Работа на клиенте через элементы интерфейса

Иногда возникает необходимость получить имена колонок прямо на клиенте без серверного вызова. Как мы выяснили, у данных формы нет коллекции колонок. Единственный путь здесь — обращение к коллекции Элементы. Посмотрим на пример:


&НаКлиенте
Процедура УзнатьКолонкиНаКлиенте()
    Для Каждого ЭлементКолонка Из Элементы.ДеревоЦен.ПодчиненныеЭлементы Цикл
        // Имя элемента формы обычно совпадает с именем колонки в данных
        ИмяПутиКДанным = ЭлементКолонка.ПутьКДанным; 
        Сообщить("Элемент формы связан с данными: " + ИмяПутиКДанным);
    КонецЦикла;
КонецПроцедуры

Внимание: У этого способа есть критическое ограничение. Вы увидите только те колонки, для которых созданы визуальные элементы на форме. Если колонка существует в данных, но она скрыта или для нее не создано «Поле ввода», этот цикл ее проигнорирует. На клиенте достоверного способа получить все колонки данных без серверного вызова не существует.

Решение 4: Кэширование имен колонок (Лучшая практика)

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

Выполним следующие шаги:

  1. Создадим на форме реквизит СписокКолонокКэш с типом Строка или ФиксированныйМассив.
  2. В процедуре ПриСозданииНаСервере заполним этот реквизит.

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

Теперь на клиенте нам достаточно просто прочитать значение СписокКолонокКэш и разбить его в массив функцией СтрРазделить(), что работает мгновенно.

Почему в именах колонок появляются UUID?

Иногда при обходе колонок вы можете встретить странные имена вроде ВидЦены2dfe5138c380.... Выясним причину этого явления. Это происходит в двух случаях:

Чтобы корректно работать с такими именами, рекомендуется всегда использовать свойство ПутьКДанным у элементов формы или хранить соответствие «Понятное имя — Системное имя» в отдельном соответствии (Map).

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

← На главную