В процессе разработки в среде 1С:Предприятие на обычных формах (например, в таких конфигурациях, как "Управление торговлей, редакция 10.3", "Управление производственным предприятием, редакция 1.3" или "Комплексная автоматизация, редакция 1.1") часто возникает задача программного открытия отчетов с уже заполненными параметрами отбора. Разработчики нередко сталкиваются с ситуацией, когда код по установке отборов написан без синтаксических ошибок, однако при открытии формы отчета параметры отбора оказываются пустыми или сбрасываются к значениям по умолчанию.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем жизненный цикл Универсального отчета и построителя отчетов, а также рассмотрим правильный алгоритм передачи параметров отбора.
Рассмотрим стандартный пример кода, который часто пишут начинающие разработчики для программного открытия отчета с установкой отбора по конкретному контрагенту:
ОтчетКонтрагента = Отчеты.ПрайсЛистПоКонтрагенту.Создать();
ОтчетКонтрагента.УстановитьНачальныеНастройки();
ЭлементОтбора = ОтчетКонтрагента.УниверсальныйОтчет.ПостроительОтчета.Отбор["Контрагент"];
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
ЭлементОтбора.Значение = ЭлементыФормы.СправочникСписок.ТекущиеДанные.Ссылка;
ОтчетКонтрагента.УниверсальныйОтчет.мВосстанавливатьНастройкиПриОткрытии = Ложь;
ФормаОтчета = Отчеты.ПрайсЛистПоКонтрагенту.ПолучитьФорму();
ФормаОтчета.Открыть();
ФормаОтчета.ОбновитьОтчет();
В данном фрагменте кода содержатся две критические архитектурные ошибки, которые полностью блокируют передачу параметров отбора в открываемый отчет. Проанализируем их подробнее.
Самая очевидная ошибка кроется в строке получения формы отчета:
ФормаОтчета = Отчеты.ПрайсЛистПоКонтрагенту.ПолучитьФорму();
В этой строке метод ПолучитьФорму() вызывается у менеджера метаданных отчета (Отчеты.ПрайсЛистПоКонтрагенту). Когда мы обращаемся к менеджеру отчета с запросом на получение формы, платформа 1С автоматически создает новый, абсолютно пустой экземпляр объекта отчета, инициализирует для него форму и возвращает ее.
При этом наш настроенный объект ОтчетКонтрагента, в котором мы кропотливо настраивали отбор по контрагенту и отключали восстановление пользовательских настроек через свойство мВосстанавливатьНастройкиПриОткрытии, просто уничтожается сборщиком мусора, так как ссылка на него теряется. В результате открывается форма абсолютно нового отчета со стандартными настройками.
Чтобы избежать этой ошибки, получать форму необходимо строго от уже созданного и настроенного объекта:
ФормаОтчета = ОтчетКонтрагента.ПолучитьФорму();
В этом случае платформа вернет форму, которая жестко связана с конкретным экземпляром объекта ОтчетКонтрагента, содержащим наши настройки.
Даже если мы исправим первую ошибку и получим форму от правильного объекта, отборы все равно могут не примениться или сброситься при вызове метода Открыть(). Давайте разберем по шагам, что происходит в этот момент:
ФормаОтчета.Открыть().ПередОткрытием и ПриОткрытии модуля формы отчета.УстановитьНачальныеНастройки(), а также происходит попытка восстановления ранее сохраненных настроек пользователя (даже если мы попытались отключить ее флагом мВосстанавливатьНастройкиПриОткрытии, в зависимости от версии конфигурации это свойство может не сработать должным образом).Чтобы обойти механизмы автоматического сброса настроек при инициализации формы Универсального отчета, мы должны изменить порядок выполнения действий. Наиболее надежный и проверенный временем способ в обычных формах заключается в том, чтобы **сначала открыть форму**, дождавшись завершения всех ее внутренних процедур инициализации, и **только после этого принудительно установить отборы** и сформировать отчет.
Давайте рассмотрим правильный, работоспособный вариант кода:
// 1. Создаем объект отчета
ОтчетКонтрагента = Отчеты.ПрайсЛистПоКонтрагенту.Создать();
// 2. Получаем форму, связанную именно с этим объектом
ФормаОтчета = ОтчетКонтрагента.ПолучитьФорму();
// 3. Открываем форму отчета на экране.
// В этот момент отрабатывают все процедуры инициализации и сброса настроек.
ФормаОтчета.Открыть();
// 4. Теперь, когда форма открыта и настройки инициализированы стандартными значениями,
// мы программно переопределяем нужный нам отбор в открытой форме.
УниверсальныйОтчетОбъект = ФормаОтчета.УниверсальныйОтчет;
ЭлементОтбора = УниверсальныйОтчетОбъект.ПостроительОтчета.Отбор["Контрагент"];
// Включаем использование отбора и задаем параметры сравнения
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
ЭлементОтбора.Значение = ЭлементыФормы.СправочникСписок.ТекущиеДанные.Ссылка;
// 5. Принудительно вызываем обновление (формирование) отчета с нашими новыми параметрами
ФормаОтчета.ОбновитьОтчет();
При таком подходе мы гарантируем, что никакие внутренние механизмы формы не перезапишут наш отбор, так как мы устанавливаем его непосредственно перед выполнением метода ОбновитьОтчет(), когда форма уже полностью готова к работе.
Если вы работаете в современной конфигурации на платформе 1С:Предприятие 8.3 с использованием управляемых форм и Системы компоновки данных (СКД), то ручное манипулирование объектами отчетов и их формами считается устаревшим подходом.
В управляемом приложении платформа предоставляет гораздо более элегантный механизм передачи параметров и отборов при открытии формы отчета через структуру параметров. Нам не нужно открывать форму, искать элементы компоновщика и вызывать методы обновления. Все решается буквально в несколько строк кода без перегрузки клиент-серверного взаимодействия:
// 1. Формируем структуру отбора
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("Контрагент", СсылкаНаКонтрагента);
// 2. Заполняем параметры формы, указывая отбор и признак автоформирования
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", СтруктураОтбора);
ПараметрыФормы.Вставить("СформироватьПриОткрытии", Истина);
// 3. Открываем форму отчета с готовыми параметрами
ОткрытьФорму("Отчет.ПрайсЛистПоКонтрагенту.Форма", ПараметрыФормы);
Платформа 1С при получении параметров с ключом Отбор автоматически применит переданную структуру к настройкам компоновщика СКД, откроет форму отчета пользователю и сразу же запустит процесс генерации данных благодаря параметру СформироватьПриОткрытии. Этот метод является наиболее стабильным, безопасным и простым в поддержке на управляемых формах.