Введение
Представьте, у вас есть несколько конфигураций, у каждой из них есть свои объекты (Справочники: номенклатура, организации; Документы: счет на оплату покупателю, реализация товаров и услуг). Эти объекты могут быть похожи, а могут и полностью отличаться, включая тип реквизитов, названия, табличные части. То есть неважно, какой объект конфигурации, у нас с вами есть несколько абсолютно разных конфигураций. Но есть "но", у этих конфигураций есть кое-что общее.
Задача звучит так: "Необходимо сделать внешнюю обработку, которая будет запускаться во всех конфигурациях независимо от того, что это за конфигурация (Бухгалтерия, Зарплата и управление, ЕРП), и отображать на форме любой из выбранных объектов. То есть все реквизиты, которые есть в этом объекте, должны быть отображены на форме. При этом не должно быть привязки к конкретному объекту конфигурации, которое делается с помощью статичного формирования пользовательского интерфейса (UI или форма)."
Интересная задача, не правда ли? Но тут возникает еще один вопрос: Задача-то интересная, но как ее выполнить?
И тут нам с вами может помочь то самое динамическое формирование элементов на форме.
Что такое динамическое формирование элементов на форме
Динамическое формирование элементов на форме - это формирование элементов формы не при создании формы изначально заданных на форме элементов, а формирование элементов в момент, определенный самим программистом с помощью кода.
Подобное создание элементов может тормозить разработку, усложнить дальнейшую поддержку и в целом не дает наглядности при разработке, но этот инструмент также дает гибкость использования UI (пользовательского интерфейса) и позволяет формировать элементы только при необходимости.
Пример формирования динамической формы
А теперь рассмотрим с вами пример подобного динамического формирования. На форме уже есть несколько элементов, в том числе две таблицы, динамически формировать будем колонки одной из этих таблиц.
Таблица на форме:

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