При разработке сложных интерфейсов в конфигурациях уровня ERP, Управление Торговлей (УТ) или Комплексная Автоматизация (КА) перед программистами часто встает задача динамического изменения состава формы. Например, добавить поля, колонки или группы в зависимости от настроек программы или прав пользователя.
Многие разработчики, привыкшие к стандартам Библиотеки Стандартных Подсистем (БСП), задаются вопросом: существует ли готовый общий модуль (API), который позволяет добавить элемент одной строкой кода, не прибегая к низкоуровневым методам платформы? В этой статье мы подробно разберем ситуацию с программным интерфейсом форм в типовых конфигурациях 1С, проанализируем возможности БСП и рассмотрим правильные подходы к решению этой задачи.
Часто возникает желание использовать код наподобие такого:
// Гипотетический пример, которого ищет разработчик
ГенерацияФорм.ДобавитьПолеВвода(ЭтаФорма, "НовоеПоле", "ПутьКДанным");
Мы проанализировали документацию БСП и структуру типовых конфигураций (ERP 2.5, УТ 11). Важно понимать следующий факт: в БСП отсутствует единый универсальный экспортный модуль-обертка для создания произвольных элементов формы.
Политика разработки фирмы "1С" подразумевает, что базовые механизмы платформы (методы Элементы.Добавить, Элементы.Вставить) являются самодостаточными. Создание универсальной обертки над ними привело бы к излишнему усложнению, так как пришлось бы дублировать сотни свойств элементов (Вид, Заголовок, События, Подсказки, РежимВыбора и т.д.) в параметрах процедур.
Однако, существуют частные случаи, которые могут ввести в заблуждение:
КомпоновкаДанныхКлиентСервер содержат методы для работы с настройками отчетов. Но они предназначены для работы с деревом настроек СКД, а не с элементами управляемой формы напрямую.УправлениеСвойствамиПереопределяемый. Использовать его для создания своих произвольных полей сложно и архитектурно неверно, если только вы не добавляете именно дополнительные реквизиты.Если готового универсального модуля нет, как же разработчики типовых решений реализуют динамические формы? Ответ кроется в анализе кода самой конфигурации.
Эффективным способом поиска примеров реализации (паттернов) является глобальный поиск по конфигурации по ключевым словам. Рассмотрим стратегию, которая привела к успеху:
Используйте глобальный поиск по строке: "#Область Формы" (в английской локализации #Region Forms).
В типовых конфигурациях (ERP, УТ) этот тег часто используется для группировки процедур, отвечающих за программную модификацию интерфейса. Обычно такие процедуры находятся в:
КлиентСервер, относящихся к конкретным подсистемам (например, ЗаказыСервер, КоммерческиеПредложенияКлиентСервер).Найдя такие области, мы увидим, что разработчики вендора используют штатные методы платформы, часто оборачивая их в локальные процедуры для конкретного документа (например, для отрисовки матрицы товаров или графика платежей). Мы можем заимствовать эти приемы для своего кода.
Разберем классический, "нативный" способ добавления элементов на форму, который является стандартом де-факто при отсутствии специализированных библиотек. Этот процесс состоит из двух этапов: изменение состава реквизитов (данных) и создание элементов интерфейса (визуализация).
Прежде чем создать поле ввода, нужно создать под него "место хранения" — реквизит формы. Это делается через метод ИзменитьРеквизиты. Обратите внимание, что этот метод работает только на Сервере.
&НаСервере
Процедура ДобавитьРеквизитПрограммно()
// Описываем тип будущего реквизита
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Строка"));
// Создаем описание типа (Квалификаторы строки, числа и т.д.)
ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипов, , Новый КвалификаторыСтроки(100));
// Создаем массив добавляемых реквизитов
ДобавляемыеРеквизиты = Новый Массив;
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("НашНовыйРеквизит", ОписаниеТипаСтрока, "", "Заголовок реквизита"));
// Применяем изменения к форме
ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
КонецПроцедуры
После того как реквизит создан, мы можем вывести его на форму. Используем коллекцию ЭтаФорма.Элементы.
&НаСервере
Процедура СоздатьЭлементИнтерфейса()
// Определяем родителя (куда добавить элемент).
// Если нужно добавить в корень, используем ЭтаФорма
РодительскаяГруппа = Элементы.ГруппаТовары; // Пример существующей группы
// Добавляем новый элемент
// УникальноеИмя - должно быть уникальным в пределах формы
// Тип("ПолеФормы") - указываем класс элемента UI
НовыйЭлемент = Элементы.Добавить("НашеНовоеПолеUI", Тип("ПолеФормы"), РодительскаяГруппа);
// Настраиваем свойства
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "НашНовыйРеквизит"; // Связываем с созданным ранее реквизитом
НовыйЭлемент.Заголовок = "Дополнительное примечание";
НовыйЭлемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Лево;
КонецПроцедуры
При программной модификации форм следует учитывать несколько критических моментов, чтобы не снизить производительность и стабильность системы.
ПриСозданииНаСервере.
ПриСозданииНаСервере, платформа отрисует её сразу в целевом виде.ПриЧтенииНаСервере или позже, это может вызвать перестроение интерфейса и лишние затраты ресурсов.ИзменитьРеквизиты) внутри обработчиков команд (нажатия кнопок) без крайней необходимости, так как это переинициализирует контекст формы.ПриИзменении), используется метод УстановитьДействие.
НовыйЭлемент.УстановитьДействие("ПриИзменении", "Подключаемый_ПриИзменении");
Важно: Процедура-обработчик (Подключаемый_ПриИзменении) должна существовать в модуле формы и быть экспортной (или доступной для вызова в данном контексте).Рассмотрим ситуацию с точки зрения современных возможностей платформы 1С:Предприятие 8.3. Если ваша задача — просто добавить поле на форму, и это поле должно быть там всегда (или почти всегда), не следует использовать программный код.
Лучшей практикой является использование Расширений конфигурации:
Элементы.Поле.Видимость = Ложь) в коде, что гораздо проще и быстрее, чем создавать их с нуля программно.Программное создание через код (как описано выше) оправдано только в высокодинамичных сценариях, например:
Подведем итоги нашего анализа:
ИзменитьРеквизиты (для данных) и Элементы.Добавить (для UI).