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