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