Как программно установить или изменить родителя группы отбора в СКД?

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

При работе с системой компоновки данных (СКД) программисты часто сталкиваются с необходимостью динамического формирования отборов. Одна из типичных задач — создание сложной иерархии условий (например, вложенные группы "И" или "ИЛИ"). Однако при попытке программно изменить родителя уже существующей группы или элемента отбора, разработчик получает ошибку: «Поле объекта недоступно для записи (Родитель)» (разобраться в причинах поможет консоль кода). В этой статье мы подробно разберем, почему так происходит и как правильно манипулировать структурой отбора.

Почему свойство «Родитель» доступно только для чтения?

Проанализируем архитектуру платформы 1С:Предприятие 8. Свойство Родитель у объектов типа ГруппаЭлементовОтбораКомпоновкиДанных и ЭлементОтбораКомпоновкиДанных предназначено исключительно для получения информации о том, в какую коллекцию входит данный элемент. В СКД иерархия определяется физическим нахождением объекта в коллекции Элементы конкретной группы или самого отбора.

Важный момент: вы не можете просто «перевесить» элемент из одной группы в другую, изменив ссылку на родителя. Единственный верный способ — это создание нового элемента в целевой коллекции и копирование в него свойств исходного элемента (или удаление старого и добавление нового).

Решение 1: Прямое добавление элемента в нужную группу

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


// Получаем коллекцию элементов отбора из компоновщика настроек
Отбор = КомпоновщикНастроек.Настройки.Отбор;

// Создаем родительскую группу (например, группа "И")
ГруппаРодитель = Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаРодитель.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ГруппаРодитель.Использование = Истина;
ГруппаРодитель.Представление = "Основное условие";

// Создаем дочернюю группу (например, группа "ИЛИ") внутри родительской
ГруппаДочерняя = ГруппаРодитель.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаДочерняя.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;
ГруппаДочерняя.Использование = Истина;

В данном примере ГруппаДочерняя автоматически получит в свойстве Родитель ссылку на ГруппаРодитель, так как она была создана через метод Добавить() коллекции элементов родителя.

Решение 2: Перемещение существующих элементов (Копирование)

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

  1. Создаем новую корневую группу.
  2. Копируем в нее все элементы из старой структуры.
  3. Очищаем старые элементы (или заменяем корень настроек).

Для упрощения этой задачи в Библиотеке стандартных подсистем (БСП) существует общий модуль КомпоновкаДанныхКлиентСервер. Метод СкопироватьЭлементы позволяет рекурсивно перенести структуру из одного источника в другой.

Рассмотрим пример реализации:


// 1. Сохраняем текущий отбор
СтарыйОтбор = КомпоновщикНастроек.Настройки.Отбор;

// 2. Создаем временную структуру настроек
НовыеНастройки = Новый НастройкиКомпоновкиДанных;
НовыйОтбор = НовыеНастройки.Отбор;

// 3. Создаем новую «супер-группу» на верхнем уровне
ГлавнаяГруппа = НовыйОтбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГлавнаяГруппа.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ГлавнаяГруппа.Использование = Истина;

// 4. Используем механизм БСП для копирования элементов из старого отбора в новую группу
КомпоновкаДанныхКлиентСервер.СкопироватьЭлементы(ГлавнаяГруппа, СтарыйОтбор, Ложь);

// 5. Загружаем новые настройки обратно в компоновщик
КомпоновщикНастроек.ЗагрузитьНастройки(НовыеНастройки);

Решение 3: Использование функций БСП для создания групп

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


// Создаем группу "ИЛИ" с помощью БСП
ПредставлениеГруппы = "Группа по контрагентам";
ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;

// Функция СоздатьГруппуЭлементовОтбора возвращает объект созданной группы
НоваяГруппа = ОбщегоНазначенияКлиентСервер.СоздатьГруппуЭлементовОтбора(
    КомпоновщикНастроек.Настройки.Отбор, 
    ПредставлениеГруппы, 
    ТипГруппы
);

// Теперь мы можем добавлять элементы уже в эту группу
Элемент = НоваяГруппа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент");
Элемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Элемент.ПравоеЗначение = Объект.Контрагент;
Элемент.Использование = Истина;

Важные нюансы и советы

Проанализируем несколько технических тонкостей, которые помогут избежать ошибок при программном управлении отборами:

Рассмотрим сложный пример формирования двойной группировки вида: ( (Условие1 И Условие2) ИЛИ (Условие3 И Условие4) ).


КоллекцияЭлементов = КомпоновщикНастроек.Настройки.Отбор.Элементы;

// Внешняя группа ИЛИ
ГруппаИЛИ = КоллекцияЭлементов.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;

// Первая вложенная группа И
ГруппаИ_1 = ГруппаИЛИ.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИ_1.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;

// Вторая вложенная группа И
ГруппаИ_2 = ГруппаИЛИ.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИ_2.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;

// Наполняем ГруппаИ_1 и ГруппаИ_2 элементами аналогично предыдущим примерам

Таким образом, мы выяснили, что программная установка родителя в СКД реализуется через правильный выбор коллекции, в которую добавляется объект. Использование методов БСП значительно ускоряет этот процесс и минимизирует количество «костылей» в коде.

← На главную