Как исправить ошибку «Метод объекта не обнаружен (Добавить)» при работе с Деревом значений в 1С?

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

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

Выясняем причину: в чем разница между Деревом значений и Данными формы?

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

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

Рассмотрим, как решить эту задачу правильно, сохранив высокую производительность системы.

Решение 1. Оптимальный способ прямого заполнения через ПолучитьЭлементы()

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

Давайте перепишем исходный код автора, добавив иерархическую структуру. Создадим две корневые ветки: «Справочники» и «Документы», а затем наполним их соответствующими объектами метаданных.

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


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

Этот способ является наиболее предпочтительным. Мы работаем напрямую со структурами формы, не тратя ресурсы сервера на лишнюю конвертацию объектов туда и обратно.

Решение 2. Обходной путь через временную конвертацию типов

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

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


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

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

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

Решение 3. Использование готовых функций Библиотеки Стандартных Подсистем (БСП)

Если вы ведете разработку в современной типовой конфигурации 1С, где развернута БСП, вам не обязательно писать велосипеды для обхода и заполнения иерархических структур. В общем модуле ОбщегоНазначения предусмотрен готовый программный интерфейс для решения этой задачи.

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

Рассмотрим пример использования этого инструмента:


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

Этот метод сочетает в себе удобство разработки, лаконичность кода и соответствие стандартам разработки фирмы «1С».

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

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

← На главную