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