Как программно добавить реквизит на управляемую форму и определить активный вариант отчета в СКД

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

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

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

Часть 1. Программное добавление реквизитов и элементов на управляемую форму

Начнем с классической проблемы, описанной автором темы. При попытке программного добавления реквизита на управляемую форму из модуля объекта внешней обработки часто возникает ошибка выполнения. Основная причина кроется в непонимании контекста исполнения кода управляемого приложения.

Платформа 1С:Предприятие жестко разграничивает клиентский и серверный контексты. Операции изменения структуры формы (такие как добавление реквизитов) могут выполняться исключительно на сервере. Более того, вызывать метод ИзменитьРеквизиты из внешнего кода напрямую у объекта полученной формы нельзя — платформа не сможет корректно инициализировать и передать измененную форму обратно на клиент.

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

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

  1. В модуле управляемой формы, которую мы хотим модифицировать, в обработчике события ПриСозданииНаСервере мы преобразуем реквизит формы во временный объект обработки с помощью метода РеквизитФормыВЗначение.
  2. Передаем саму форму (контекст ЭтотОбъект) в экспортную процедуру модуля объекта нашей обработки.
  3. В модуле объекта обработки выполняем добавление реквизитов и элементов интерфейса, используя контекст переданной формы.

Рассмотрим пример кода в модуле модифицируемой управляемой формы:


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

Теперь проанализируем код в модуле объекта обработки, который выполняет непосредственное добавление реквизитов и элементов. Обратите внимание, что добавление реквизита происходит через создание объекта РеквизитФормы и вызов метода ИзменитьРеквизиты, после чего создается элемент формы с привязкой к созданному пути к данным:


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

Использование этого подхода гарантирует бесконфликтную работу платформы с динамическими реквизитами формы без генерации ошибок об отсутствии методов.

Часть 2. Определение активного варианта настроек в СКД

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

Выясним, как это сделать наиболее изящно и профессионально.

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

Рассмотрим, как получить наименование и уникальный ключ текущего варианта отчета в модуле объекта отчета:


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

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

Для этого в модуле формы отчета переопределим стандартное событие ПриЗагрузкеВариантаНаСервере:


&НаСервере
Процедура ПриЗагрузкеВариантаНаСервере(Настройки)
    
    // Записываем ключ выбранного варианта в настройки компоновщика перед компоновкой
    Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("КлючВарианта", КлючТекущегоВарианта);
    
КонецПроцедуры

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Читаем переданный из формы ключ варианта
    КлючВарианта = "";
    КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Свойство("КлючВарианта", КлючВарианта);
    
    Если КлючВарианта = "ОсобыйВариантПродаж" Тогда
        
        // Отменяем стандартный вывод отчета
        СтандартнаяОбработка = Ложь;
        
        // Модифицируем текст запроса непосредственно в схеме компоновки
        СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Запрос = 
            "ВЫБРАТЬ
            |   ПродажиОбороты.Номенклатура КАК Номенклатура,
            |   ПродажиОбороты.КоличествоОборот КАК Количество
            |ИЗ
            |   РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты";
            
        // Запускаем программный вывод отчета с измененной схемой
        КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
        МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
        
        ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
        ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
        
        ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
        ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
        ПроцессорВывода.Вывести(ПроцессорКомпоновки);
        
    КонецЕсли;
    
КонецПроцедуры

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

← На главную