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