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