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