Разработка отчетов на системе компоновки данных (СКД) в управляемых формах 1С часто преподносит сюрпризы разработчикам. Типичная задача: при открытии отчета автоматически заполнить определенный параметр (например, конкретный склад, организацию или период) определенным значением по умолчанию. Однако стандартный подход с заполнением параметров в обработчике ПриСозданииНаСервере формы отчета часто не приносит желаемого результата — поля на форме остаются пустыми или сбрасываются. Еще более интересная задача — сделать так, чтобы пользователь видел этот параметр, но не мог самостоятельно изменить его значение.
В этой статье мы подробно разберем механизмы работы компоновщика настроек, выясним причину сброса программно установленных параметров, рассмотрим правильные методы инициализации значений и научимся управлять доступностью элементов формы пользовательских настроек.
Давайте проанализируем ситуацию, с которой сталкивается большинство разработчиков. При попытке напрямую изменить коллекцию настроек в событии формы ПриСозданииНаСервере код выглядит логично и просто:
ПараметрыСКД = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы;
НайденныйПараметр = ПараметрыСКД.Найти("Склад");
Если НайденныйПараметр <> Неопределено Тогда
НайденныйПараметр.Значение = Справочники.Склады.НайтиПоНаименованию("Основной склад");
НайденныйПараметр.Использование = Истина;
КонецЕсли;
Однако при открытии отчета на форме поле параметра "Склад" все равно оказывается незаполненным. Почему так происходит? Дело в жизненном цикле инициализации управляемой формы отчета. В платформе 1С процессы выполняются в следующей строгой последовательности:
ПриСозданииНаСервере. Наш программный код выполняется и записывает значение в настройки компоновщика.По этой причине устанавливать значения параметров в ПриСозданииНаСервере напрямую через КомпоновщикНастроек.Настройки чаще всего бесполезно, если эти параметры вынесены в область пользовательских настроек на форму (отмечены "звездочкой" в схеме компоновки данных).
Для того чтобы гарантированно перехватить процесс инициализации настроек и установить нужное значение параметров, мы можем использовать специализированные стандартные обработчики событий формы. Одним из наиболее надежных мест является процедура ПередЗагрузкойВариантаНаСервере.
Этот обработчик вызывается платформой в тот момент, когда структура настроек отчета инициализируется на сервере, но пользовательские настройки еще не успели окончательно заблокировать программное изменение данных. Рассмотрим пример реализации:
&НаСервере
Процедура ПередЗагрузкойВариантаНаСервере(Настройки)
// Инициализируем требуемое значение параметра
ПарамСклад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
// Устанавливаем значение параметра напрямую в структуру настроек варианта
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Склад", ПарамСклад);
КонецПроцедуры
Использование метода УстановитьЗначениеПараметра() позволяет безопасно обновить значение параметра в передаваемой коллекции настроек. Данный метод хорош тем, что он автоматически активирует использование параметра (свойство Использование = Истина).
Если нам необходимо жестко управлять параметром, который вынесен в область пользовательских настроек, правильнее всего изменять значение непосредственно в коллекции ПользовательскиеНастройки компоновщика настроек. Для этого мы должны найти соответствующий элемент по его уникальному идентификатору пользовательской настройки.
Рассмотрим по шагам, как реализовать этот алгоритм в коде формы:
&НаСервере
Процедура УстановитьПараметрВПользовательскихНастройках()
ИмяПараметра = "Склад";
НужноеЗначение = Справочники.Склады.НайтиПоНаименованию("Основной склад");
// 1. Находим описание параметра в основных настройках компоновщика
ПараметрКомпоновки = Новый ПараметрКомпоновкиДанных(ИмяПараметра);
НастройкаПараметра = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(ПараметрКомпоновки);
Если НастройкаПараметра <> Неопределено Тогда
// Получаем уникальный идентификатор пользовательской настройки данного параметра
ИдентификаторНастройки = НастройкаПараметра.ИдентификаторПользовательскойНастройки;
// 2. Если параметр вынесен в пользовательские настройки, ищем его в соответствующей коллекции
Если ЗначениеЗаполнено(ИдентификаторНастройки) Тогда
ЭлементПользовательскойНастройки = Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ИдентификаторНастройки);
Если ЭлементПользовательскойНастройки <> Неопределено Тогда
// Устанавливаем значение и флаг использования напрямую в пользовательской настройке
ЭлементПользовательскойНастройки.Значение = НужноеЗначение;
ЭлементПользовательскойНастройки.Использование = Истина;
КонецЕсли;
Иначе
// Если параметр не в пользовательских настройках, меняем его в основных
НастройкаПараметра.Значение = НужноеЗначение;
НастройкаПараметра.Использование = Истина;
EndЕсли;
КонецЕсли;
КонецПроцедуры
Этот метод является наиболее универсальным и отказоустойчивым. Он гарантирует, что значение будет выведено в поле ввода на управляемой форме отчета, даже если пользователь ранее сохранял другие настройки для этого отчета.
Теперь перейдем ко второй части задачи: параметр должен отображаться на форме, чтобы пользователь видел, по какому складу или организации сформирован отчет, но само поле ввода должно быть заблокировано для изменения (режим "Только просмотр").
Сложность здесь заключается в том, что элементы пользовательских настроек СКД генерируются на управляемой форме динамически в процессе ее отрисовки платформой. Мы не можем просто обратиться к полю ввода по статическому имени вроде Элементы.Склад, так как такого элемента на этапе конфигурации формы просто не существует.
Для решения этой проблемы нам необходимо выполнить обход коллекции динамических элементов формы, найти тот, который связан с нашей пользовательской настройкой параметра, и программно установить для него свойство ТолькоПросмотр = Истина. Разберем, как это сделать в модуле формы отчета:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ЗаблокироватьРедактированиеПараметра("Склад");
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьИдентификаторНастройкиПараметра(Компоновщик, ИмяПараметра)
ПараметрКомпоновки = Новый ПараметрКомпоновкиДанных(ИмяПараметра);
НастройкаПараметра = Компоновщик.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(ПараметрКомпоновки);
Если НастройкаПараметра <> Неопределено Тогда
Возврат НастройкаПараметра.ИдентификаторПользовательскойНастройки;
КонецЕсли;
Возврат Неопределено;
КонецФункции
&НаКлиенте
Процедура ЗаблокироватьРедактированиеПараметра(ИмяПараметра)
// Получаем идентификатор пользовательской настройки на сервере
ИдентификаторНастройки = ПолучитьИдентификаторНастройкиПараметра(Отчет.КомпоновщикНастроек, ИмяПараметра);
Если НЕ ЗначениеЗаполнено(ИдентификаторНастройки) Тогда
Возврат;
КонецЕсли;
// Формируем ожидаемый путь к данным для элемента формы
// Платформа связывает элементы настроек по пути к данным вида:
// "Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[Индекс].Значение"
Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
// Проверяем, является ли элемент полем ввода и связан ли он с пользовательскими настройками
Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") Тогда
ПутьКДанным = ЭлементФормы.ПутьКДанным;
// Проверяем, содержит ли путь ссылку на элементы пользовательских настроек
Если Найти(ПутьКДанным, "ПользовательскиеНастройки") > 0 Тогда
// Извлекаем индекс элемента в коллекции пользовательских настроек
// Строка выглядит как: "Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[0].Значение"
ЛеваяГраница = Найти(ПутьКДанным, "[");
ПраваяГраница = Найти(ПутьКДанным, "]");
Если ЛеваяГраница > 0 И ПраваяГраница > 0 Тогда
ИндексСтрокой = Сред(ПутьКДанным, ЛеваяГраница + 1, ПраваяГраница - ЛеваяГраница - 1);
Попытка
Индекс = Число(ИндексСтрокой);
ЭлементНастройки = Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы[Индекс];
// Сверяем идентификатор элемента формы с искомым идентификатором параметра
Если ЭлементНастройки.ИдентификаторПользовательскойНастройки = ИдентификаторНастройки Тогда
// Устанавливаем свойство "Только просмотр" для поля на форме
ЭлементФормы.ТолькоПросмотр = Истина;
Прервать; // Элемент найден и заблокирован, выходим из цикла
КонецЕсли;
Исключение
// Игнорируем ошибки приведения типов при нетипичном поведении путей
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если вам вообще не требуется показывать параметр пользователю на форме (или некритично его визуальное отображение в области шапки формы отчета), но при этом СКД должна гарантированно получить нужное жесткое значение при формировании результата отчета, лучшим решением будет перенос логики в модуль объекта отчета.
В модуле объекта отчета мы можем переопределить стандартную процедуру ПриКомпоновкеРезультата. Данный метод сработает непосредственно перед выполнением запроса к базе данных, и никакие действия пользователя на форме не смогут обойти эту установку:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Находим параметр СКД по имени
ПараметрСклад = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Склад");
Если ПараметрСклад <> Неопределено Тогда
ПараметрСклад.Значение = Справочники.Склады.НайтиПоНаименованию("Основной склад");
ПараметрСклад.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Этот способ максимально надежен для жестко заданных бизнес-алгоритмов формирования отчетов, однако учитывайте, что при использовании данного подхода значение на форме отчета в режиме реального времени отображаться не будет — оно применится исключительно в момент нажатия кнопки "Сформировать".
Мы рассмотрели особенности работы с параметрами компоновки данных в управляемых формах 1С 8.3. Подведем итоги работы с параметрами:
ПриСозданииНаСервере формы для изменения параметров, если они вынесены в пользовательские настройки.ПередЗагрузкойВариантаНаСервере или напрямую изменяйте элементы коллекции ПользовательскиеНастройки компоновщика.ПриКомпоновкеРезультата модуля объекта.ЭтаФорма.Элементы с анализом свойства ПутьКДанным и установкой флага ТолькоПросмотр = Истина.