Почему пропадают настройки компоновщика СКД при передаче между отчетами и как это исправить?

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

При разработке сложных отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с необходимостью передать настройки (отборы, параметры, значения) из одного отчета в другой. Типичная ситуация: мы программно заполняем КомпоновщикНастроек в форме вызываемого отчета, видим в отладчике, что данные на месте, но как только управление переходит в модуль объекта для формирования результата, параметры магическим образом очищаются. Рассмотрим подробнее, почему это происходит и как гарантированно доставить данные до модуля объекта.

Анализируем причину исчезновения настроек

Для начала разберем, как устроен КомпоновщикНастроек. Это не просто плоская структура, а трехуровневая система, состоящая из следующих коллекций:

  1. Настройки (Settings): Основная структура, которую мы видим в схеме компоновки.
  2. Пользовательские настройки (UserSettings): Те элементы, которые вынесены на форму для изменения пользователем.
  3. Фиксированные настройки (FixedSettings): Жестко заданные настройки, которые не могут быть изменены пользователем и имеют приоритет.

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

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

Решение 1: Использование временного хранилища (практический метод)

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

Шаг 1. Подготовка данных в вызывающем отчете. Сначала мы формируем структуру необходимых нам данных и помещаем её во временное хранилище. Адрес этого хранилища мы передадим как параметр формы.


&НаСервере
Функция ПолучитьАдресНастроекВоВременномХранилище(СтруктураДанных)
    // Формируем структуру параметров, которые хотим передать
    ПараметрыДляПередачи = Новый Структура;
    ПараметрыДляПередачи.Вставить("НачалоПериода", СтруктураДанных.НачалоПериода);
    ПараметрыДляПередачи.Вставить("КонецПериода", СтруктураДанных.КонецПериода);
    ПараметрыДляПередачи.Вставить("Номенклатура", СтруктураДанных.Номенклатура);
    
    // Помещаем во временное хранилище, привязывая к уникальному идентификатору формы
    Возврат ПоместитьВоВременноеХранилище(ПараметрыДляПередачи, ЭтаФорма.УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура ВызватьВторойОтчет(Команда)
    Адрес = ПолучитьАдресНастроекВоВременномХранилище(СформированныеДанные);
    ПараметрыФормы = Новый Структура("АдресНастроек, СформироватьПриОткрытии", Адрес, Истина);
    ОткрытьФорму("Отчет.НужныйОтчет.Форма.ФормаОтчета", ПараметрыФормы);
КонецПроцедуры

Шаг 2. Обработка в вызываемом отчете. В форме второго отчета нам нужно сохранить этот адрес, чтобы модуль объекта мог к нему обратиться. Для этого добавим реквизит отчета АдресНастроекХранилище (тип Строка).


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

Шаг 3. Извлечение данных в модуле объекта. Теперь в процедуре ПриКомпоновкеРезультата мы можем напрямую получить данные, минуя капризный КомпоновщикНастроек формы.


Процедура ПриКомпоновкеРезультата(ТабличныйДокумент, ДанныеРасшифровки, СтандартнаяОбработка)
    
    Если ЗначениеЗаполнено(АдресНастроекХранилище) Тогда
        // Получаем наши данные из хранилища
        ПереданныеНастройки = ПолучитьИзВременногоХранилища(АдресНастроекХранилище);
        
        // Устанавливаем параметры компоновщика напрямую перед формированием
        Для Каждого Элемент Из ПереданныеНастройки Цикл
            ПараметрСКД = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(Элемент.Ключ);
            Если ПараметрСКД <> Неопределено Тогда
                ПараметрСКД.Значение = Элемент.Значение;
                ПараметрСКД.Использование = Истина;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
    // Далее стандартный или программный вывод...
КонецПроцедуры

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

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

Проанализируем ситуацию: просто вызвать ЗагрузитьНастройки() недостаточно. После этого нужно сопоставить идентификаторы. Рассмотрим пример правильной установки параметра:


&НаСервере
Процедура УстановитьПараметрСКД(ИмяПараметра, Значение)
    // 1. Устанавливаем в основном компоновщике
    Параметр = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(ИмяПараметра);
    Если Параметр <> Неопределено Тогда
        Параметр.Значение = Значение;
        Параметр.Использование = Истина;
        
        // 2. Обязательно находим этот же параметр в ПОЛЬЗОВАТЕЛЬСКИХ настройках
        Идентификатор = Параметр.ИдентификаторПользовательскойНастройки;
        Если ЗначениеЗаполнено(Идентификатор) Тогда
            Для Каждого ЭлементПольз Из Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы Цикл
                Если ЭлементПольз.ИдентификаторПользовательскойНастройки = Идентификатор Тогда
                    ЭлементПольз.Значение = Значение;
                    ЭлементПольз.Использование = Истина;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Решение 3: Использование Фиксированных настроек

Если ваша задача — передать параметры «жестко», так чтобы пользователь не мог их случайно изменить или чтобы они гарантированно не перекрылись настройками формы, используйте ФиксированныеНастройки. Посмотрим на пример:


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

Важный нюанс: параметры, установленные в ФиксированныеНастройки, не будут доступны для редактирования пользователем на форме. Они суммируются с основными настройками при компоновке макета.

Рекомендации по отладке

Выясним, на каком этапе происходит сбой, используя следующие советы:

  1. Проверьте свойство СтандартнаяОбработка в процедуре ПриКомпоновкеРезультата. Если вы формируете отчет полностью программно, установите её в Ложь.
  2. Проанализируйте значение КлючНазначенияИспользования при открытии формы. Если у отчета есть сохраненные автоматические настройки, 1С может применить их в самом конце инициализации формы, затирая ваш программный код. Попробуйте передать уникальный ключ в параметрах ОткрытьФорму.
  3. Убедитесь, что в модуле объекта вы обращаетесь к ЭтотОбъект.КомпоновщикНастроек. Иногда разработчики случайно создают новый экземпляр компоновщика на основе схемы, теряя связь с тем объектом, который был настроен в форме.

Использование временного хранилища, как показал опыт участников обсуждения, является наиболее стабильным «обходным путем», когда штатные механизмы синхронизации компоновщика ведут себя непредсказуемо.

← На главную