Как программно установить схему компоновки данных в управляемой форме и избежать потери полей

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

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

Выясняем причину проблемы: почему исчезают доступные поля

Проанализируем ситуацию. Основная причина кроется в особенностях работы КомпоновщикаНастроек. Этот объект состоит из нескольких частей, и одна из самых важных — Настройки.ДоступныеПоляВыбора. Эти поля не хранятся в самом компоновщике «намертво», они строятся динамически на основании связи компоновщика с конкретной схемой (СКД).

Когда мы на сервере меняем схему в объекте отчета, мы создаем новый контекст. После выполнения ЗначениеВРеквизитФормы данные передаются на клиент. Однако объект ИсточникДоступныхНастроекКомпоновкиДанных, который связывает компоновщик со схемой, не сериализуется и не передается между сервером и клиентом автоматически в полном объеме. В итоге на клиенте КомпоновщикНастроек «забывает», откуда ему брать описание полей. Чтобы исправить это, нам необходимо восстановить эту связь вручную.

Шаг 1. Подготовка схемы и передача ее через временное хранилище

Рассмотрим правильный алгоритм действий на сервере. Нам нужно не просто назначить схему, но и поместить ее в такое место, откуда клиент сможет ее «подцепить». Лучшее решение — Временное хранилище. При этом крайне важно использовать УникальныйИдентификатор формы, чтобы данные жили столько же, сколько открыта форма отчета.

Создадим серверную процедуру для инициализации схемы:


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

КонецПроцедуры

Шаг 2. Инициализация компоновщика на клиенте

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


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

Дополнительные нюансы и решение ошибки «Не найдено поле»

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

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


// В серверной процедуре после загрузки основных настроек
ОтчетОбъект.КомпоновщикНастроек.ЗагрузитьПользовательскиеНастройки(ОтчетОбъект.КомпоновщикНастроек.ПользовательскиеНастройки);

Также обратим внимание на важный момент при работе с расширением формы отчета. Если ваша форма имеет тип УправляемаяФорма и связана с отчетом, у нее есть встроенные механизмы работы с компоновщиком. Чтобы система «поняла», что структура изменилась, иногда требуется вызвать метод СкомпоноватьРезультат(). Рассмотрим пример:


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

Альтернативный подход: Модификация существующей схемы

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


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

Подведем итоги

Для успешной программной установки СКД в управляемой форме мы должны придерживаться строгого порядка действий:

  1. Работаем через объект: Используем РеквизитФормыВЗначение для получения доступа к свойствам схемы.
  2. Храним схему: Обязательно помещаем новую СКД во временное хранилище с привязкой к УникальномуИдентификатору формы.
  3. Связываем контексты: Вызываем Инициализировать() для КомпоновщикаНастроек и на сервере, и на клиенте.
  4. Чистим старое: При необходимости очищаем пользовательские настройки и элементы выбора, если они конфликтуют с новой схемой.
  5. Обновляем интерфейс: Используем ОбновитьОтображениеДанных() для визуального обновления состава полей в форме настроек.

Соблюдение этих правил позволит вам создавать гибкие отчеты, которые могут менять свою структуру «на лету» в зависимости от действий пользователя, сохраняя при этом полную работоспособность всех механизмов системы компоновки данных.

← На главную